欢迎来到Cefler的博客😁
🕌博客主页:折纸花满衣
🏠个人专栏:题目解析
目录
👉🏻线程概念
🌈理论概念
在Linux系统中,线程是指在同一进程内并发执行的一组指令序列 。线程共享同一进程的地址空间、文件描述符等资源,但每个线程有自己的栈空间和寄存器集,使得线程之间可以独立运行,实现并发执行。
Linux系统使用轻量级进程(LWP)来实现线程,也就是说,每个线程都被视为一个独立的轻量级进程。这种设计使得线程的创建和切换开销较小,能够更高效地利用系统资源。
在Linux中,线程的创建和管理通常通过POSIX线程库(pthread)来实现。开发者可以使用pthread库中提供的函数来创建线程、控制线程的执行顺序、进行线程同步等操作。
🌈通俗理解线程
1.线程是比进程更加轻量化的一种执行流
/线程是在进程内部执行的一种执行流
2.线程是CPU调度的基本单位/进程是承担系统资源的基本实体
进程的创建很麻烦,要构建进程地址空间,页表,加载代码数据、动静态库,建立映射关系等多项操作,而线程只要创建一个描述PCB即可,因为线程在进程的地址空间中运行,前人栽树后人乘凉,只用共享进程地址空间中的资源就好了。
在linux下,线程就是轻量级进程,我们以前学的进程,是一个进程内只有一个执行流,而现实是,一个进程内会有多个执行流,进程创建初始会伴有一个初始PCB,后面产生多个执行流后再根据先描述再组织创建对应的PCB,每个PCB之间的地位相同
👉🏻线程优缺点
线程作为一种并发编程的重要工具,具有许多优点和缺点。以下是线程的主要优缺点总结:
优点:
- 资源共享:线程可以方便地共享同一进程的资源,如内存空间、文件描述符等,减少资源开销和提高效率。
- 响应速度快:线程之间切换的开销较小,能够实现快速的响应和处理多任务。
- 并发性能:线程可以利用多核处理器实现并行计算,提高系统的性能和吞吐量。
- 简化编程:使用线程可以简化程序设计,将复杂任务拆分为多个线程并发执行,提高程序的可维护性和扩展性。
缺点:
-
竞态条件:线程间的并发执行可能导致竞态条件(Race Condition),需要使用同步机制(如互斥锁、信号量)来解决,增加了编程复杂性。
-
死锁:线程间的相互等待资源导致的死锁是并发编程中常见的问题,需要仔细设计和管理线程之间的依赖关系。
-
调试困难:多线程程序的调试和测试比单线程程序更为复杂,因为涉及到线程间的交互和并发执行。
-
资源消耗:每个线程都需要独立的栈空间和线程上下文,可能会占用较多的系统资源,限制了线程数量的上限。
👉🏻创建线程(代码示例)
以下是一个使用 pthread.h
头文件和 pthread_create
函数创建线程的 C++ 示例代码:
cpp
#include <iostream>
#include <pthread.h>
// 线程函数,打印一段文字
void* printMessage(void* arg) {
for(int i = 0; i < 5; ++i) {
std::cout << "Hello, I am a thread!" << std::endl;
}
return nullptr;
}
int main() {
pthread_t tid;
// 创建一个新线程,并指定线程函数为 printMessage
int ret = pthread_create(&tid, nullptr, printMessage, nullptr);
if (ret != 0) {
std::cerr << "Error creating thread: " << ret << std::endl;
return 1;
}
// 主线程继续执行自己的任务
for(int i = 0; i < 3; ++i) {
std::cout << "Hello from the main thread!" << std::endl;
}
// 等待子线程执行完毕
pthread_join(tid, nullptr);
return 0;
}
在这个示例中,我们使用 pthread.h
头文件中的 pthread_create
函数来创建一个新线程。主线程和子线程分别打印不同的文本内容,最后主线程调用 pthread_join
函数等待子线程执行完毕。希望这个示例对您有所帮助!
以下是 pthread_create
函数和 pthread_join
函数的简要介绍:
🍒pthread_create 函数
pthread_create
函数用于创建一个新的线程,并指定线程函数。它的原型如下:
cpp
#include <pthread.h>
int pthread_create(pthread_t* thread, const pthread_attr_t* attr,
void* (*start_routine)(void*), void* arg);
thread
:一个指向pthread_t
类型变量的指针,用于存储新线程的 ID;attr
:一个指向pthread_attr_t
类型变量的指针,用于设置线程属性(通常指定为nullptr
);start_routine
:一个指向线程函数的指针,该函数在新线程中执行;arg
:一个指针参数,传递给线程函数作为参数。
pthread_create
函数返回 0 表示成功,否则表示失败。
🍒pthread_join 函数
pthread_join
函数用于等待一个线程执行完毕,并回收其资源。它的原型如下:
cpp
#include <pthread.h>
int pthread_join(pthread_t thread, void** retval);
thread
:待等待的线程的 ID;retval
:一个指向指针的指针,用于存储线程函数的返回值(通常指定为nullptr
)。
pthread_join
函数阻塞当前线程,直到指定的线程执行完毕。如果指定的线程已经结束,那么 pthread_join
函数会立即返回。成功返回 0,否则返回一个非零值表示出错。
LWP(轻量级进程)
LWP(Lightweight Process,轻量级进程)是一种在类 Unix 操作系统中用于实现线程的机制。在这种机制下,每个进程可以包含多个轻量级进程(LWP),每个 LWP 都有自己的程序计数器、栈、寄存器和状态。LWP 通常由操作系统内核直接管理,因此比传统的线程更轻量级。
LWP 的优点包括:
- 更快的线程创建和上下文切换:由于 LWP 是由操作系统内核管理的,因此线程的创建和上下文切换开销较小。
- 更好的并发性能:LWP 可以更有效地利用多核处理器和多处理器系统,提高并发性能。
LWP 在许多类 Unix 系统中被广泛使用,例如 Solaris、FreeBSD 和 AIX 等系统。它们通常与用户级线程库(如 POSIX 线程库)结合使用,通过将用户级线程映射到轻量级进程来实现线程并发。
这里顺便科普一下TTY
TTY(Teletype,电传打字机)是指一种用于与计算机进行交互的设备或接口。在早期的计算机系统中,TTY通常指代终端设备,用户可以通过终端设备与计算机进行交互,输入命令并查看输出结果。随着技术的发展,TTY这个术语逐渐演变为代表任何与计算机进行交互的设备、接口或会话。
在类 Unix 系统中,TTY通常指代以下几种内容之一:
- 物理终端设备:早期的计算机系统使用物理终端设备(如电传打字机或显示器)作为用户与计算机进行交互的工具。每个物理终端设备都被称为一个TTY。
- 虚拟终端设备:在类 Unix 系统中,虚拟终端设备也被称为TTY。在多用户环境下,每个用户登录到系统后通常会分配一个虚拟终端设备,用于与系统进行交互。
- 伪终端设备:伪终端设备(pseudo-TTY,PTY)是一种用于在用户进程和程序之间建立通信连接的设备接口,例如用于在终端模拟器中运行的 shell 会话。
总之,TTY是一个广义的术语,指代用于与计算机进行交互的设备、接口或会话,包括物理终端设备、虚拟终端设备和伪终端设备等。
👉🏻如何理解线程为轻量级进程
线程被称为轻量级进程是因为它相比于传统的进程来说具有以下几个轻量级的特点:
-
资源开销低:线程在创建、切换和销毁时所需的资源开销相对较低。与进程相比,线程共享了同一进程的地址空间、文件描述符等资源,不需要像进程那样独立拥有自己的资源副本,因此节约了内存和系统资源。
-
切换快速:由于线程共享进程的地址空间,在进行线程切换时只需保存和恢复少量的上下文信息,切换速度较快。而进程之间的切换需要保存和恢复更多的上下文信息,因此较慢。
-
通信方便:线程之间可以通过共享内存等方式轻松地进行通信,不需要像进程那样使用进程间通信(IPC)的机制来进行通信,因此通信成本更低。
-
并发性高:由于线程共享进程的资源,线程之间的通信和同步更加方便快捷,能够更好地实现并发执行,提高系统的性能和响应速度。
-
灵活性强:线程的创建和销毁比进程更加灵活,可以根据需要动态地创建和销毁线程,适应不同的任务需求,提高系统的灵活性和效率。
总的来说,线程作为轻量级进程体现在资源开销低、切换快速、通信方便、并发性高和灵活性强等方面。这些特点使得线程在实现并发编程时更加高效和灵活,适用于各种需要并发处理的场景。
cache(缓存)
在 CPU 调度中,缓存(cache)是一个非常重要的概念。CPU 的缓存通常分为三级:一级缓存(L1 Cache)、二级缓存(L2 Cache)和三级缓存(L3 Cache)。缓存的存在主要是为了加快 CPU 对数据的访问速度,提高计算效率。
在 CPU 调度中,缓存对性能有着重要影响,主要体现在以下几个方面:
- 命中率:缓存命中率是衡量缓存性能的重要指标。当 CPU 需要访问数据时,如果该数据在缓存中已经存在,则称为缓存命中,可以直接从缓存中读取数据,避免访问主存,提高访问速度。高缓存命中率可以减少对主存的访问次数,提高整体性能。
- 缓存替换策略:当缓存空间不足时,需要根据一定的策略决定哪些数据会被替换出去。常见的缓存替换策略包括最近最少使用(LRU)、先进先出(FIFO)等。合理的缓存替换策略可以提高缓存的利用率,减少缓存未命中带来的性能损失。
- 缓存一致性:多核 CPU 中,每个核心都有自己的缓存,可能导致缓存之间的数据不一致。为了保持数据的一致性,需要使用一致性协议(如 MESI 协议)来协调不同核心之间的数据更新和同步操作。
- 缓存预取:为了提高缓存命中率,CPU 会预先将可能需要访问的数据加载到缓存中。通过智能的缓存预取策略,可以减少访存延迟,提高程序执行效率。
如上便是本期的所有内容了,如果喜欢并觉得有帮助的话,希望可以博个点赞+收藏+关注🌹🌹🌹❤️ 🧡 💛,学海无涯苦作舟,愿与君一起共勉成长