🎬慕斯主页:修仙—别有洞天
♈️今日夜电波:会いたい—Naomile
1:12━━━━━━️💟──────── 4:59
🔄 ◀️ ⏸ ▶️ ☰
💗关注👍点赞🙌收藏您的每一次鼓励都是对我莫大的支持😍
目录
Linux线程的概念
定义
从进程理解线程
Linux线程的理解
局部性原理
概念
线程切换为什么效率高?
Linux线程的概念
定义
课本上的定义:线程是比进程更轻量化的一种执行流,线程是在进程内部执行的一种执行流。大白话:线程是CPU调度的基本单位,进程是承担系统资源的基本实体。
对于Linux线程详细的定义:在一个程序里的一个执行路线就叫做线程(thread)。更准确的定义是:线程是“一个进程内部的控制序列。一切进程至少都有一个执行线程。线程在进程内部运行,本质是在进程地址空间内运行。在Linux系统中,在CPU眼中,看到的PCB都要比传统的进程更加轻量化。透过进程虚拟地址空间,可以看到进程的大部分资源,将进程资源合理分配给每个执行流,就形成了线程执行流 。
从进程理解线程
我们都知道Linux中的一个进程是由对应的PCB、进程地址空间、页表组成的。
大致的图示如下:
从上面进程的大致示意图可见,如果我们要创建一个进程,还是挺麻烦的,它要创建对应的PCB来管理,要加载各种各样的数据,涉及到IO等等。可以发现成本是挺高的。进程在创建时需要做很多工作。而线程就是在进程创建完成后,只需再创建“PCB”指向该进程的地址空间,再将代码数据等等拆解成几部分,分别让这些“PCB”进行管理对应的部分,他无需再进行资源的申请等等操作,只需进行资源的分配即可。CPU在识别到这些“PCB”时,他就会执行该进程的一部分代码、一部分数据,我们把这种比传统的进程更轻的概念叫做“线程”。当然,由于线程访问的是同一块地址空间,那么他们是很容易实现某一部分代码、数据的共享的。
而如果OS如果要支持线程,那么也是需要管理线程的,那么就需要按照六字真言:“先描述,在组织”来进行管理。对此OS中有两种管理线程的方法:方法一:按照像上述进程一样创建PCB,额外的像进程一样创建名为:TCB(Thread Control Block)来描述,再像进程一样创建调度队列、阻塞队列、运行队列、优先级等等等等。还需要对应的数据结构、算法等等来维护起来。方法二:从方法一可以知道线程所需的属性跟进程是很相似的,我们可以“拿PCB来充当TCB”,可以直接复用进程的管理方法来管理线程。在Linux中,我们就是使用方法二来管理线程的,很明显方法二更简单,更加可靠,健壮性更,更好维护。Linux中线程也叫做:轻量级进程(LWP)(light weight process)大致图示如下:
从上图可知,Linux中其实不存在实际意义上的线程,他只是利用进程的数据结构来模拟了线程,所以CPU在调度时,他不管进程还是线程,他看到一个PCB就会执行对应的方法,他们都可以被称为“轻量级进程”。因此,上面对应的线程的执行流<=进程的执行流。
Linux线程的理解
通过代码来理解Linux线程(对于下面的一些线程相关函数后续详细介绍):
#include <iostream>
#include <unistd.h>
#include <pthread.h>
#include <sys/types.h>
#include <unistd.h>
int gcnt = 100;
// 新线程
void *ThreadRoutine(void *arg)
{
const char *threadname = (const char *)arg;
while (true)
{
std::cout << "I am a new thread: " << threadname << ", pid: " << getpid() << "gcnt: " << gcnt << " &gcnt: " << &gcnt << std::endl;
gcnt--;
sleep(1);
}
}
int main()
{
pthread_t tid;
pthread_create(&tid, NULL, ThreadRoutine, (void *)"thread 1");//创建进程
while (true)
{
std::cout << "I am main thread"
<< ", pid: " << getpid() << "gcnt: " << gcnt << " &gcnt: " << &gcnt << std::endl;
sleep(1);
}
return 0;
}
如下图可知:我们创建了一个线程,在创建线程后,可以很明显的看到我们共享了全局变量。对于创建了一个线程前,我们可以理解为原来只有一个线程(也就是进程)。后来创建了一个线程后,我们就拥有了两个线程,通过传入对应的函数即可区分两个进程,他们还可以共享同一段代码(全局变量)。
我们可以通过以下代码查看线程:
ps -aL
局部性原理
概念
局部性原理是指在程序执行期间,无论是指令还是数据的访问都倾向于聚集在一个较小的连续区域中。它主要分为两种类型:
- 时间局部性:如果一个指令或数据刚刚被访问过,那么它将很可能在不久的将来再次被访问。这种现象是由于程序中存在循环和迭代等结构,导致相同的指令或数据被重复使用。
- 空间局部性:如果一个指令或数据被访问,那么与其相邻的指令或数据也很可能即将被访问。这是因为程序往往是顺序执行的,指令和数据在内存中的位置通常是连续的,因此访问也是连续的。
局部性原理是计算机体系结构中的一个重要概念,它直接影响了CPU缓存的设计和操作系统的内存管理策略。了解和利用局部性原理,可以帮助开发者编写更高效的程序,同时也指导硬件设计者优化处理器性能。
线程切换为什么效率高?
CUP中存在着一个硬件叫做cache,他通常用于用于存储最近访问的数据和指令以提高计算机性能。
局部性原理给预加载机制提供了理论基础,预加载机制可以将一部分代码预先加载到缓冲区里,如果CPU正在访问第10行代码,以后很大概率会访问附近的代码,所以一旦访问到第10行就会把10行附近的数据和代码全部加载到内存中或者CPU的cache中。保存在cache中的数据叫做热数据。cache在缓存时是以线程为单位的,线程间切换不需要切换cache,因为他们同属于一个进程,而进程间切换需要切换cache,重新预加载。为什么线程切换为什么比进程高?因为:1、寄存器少。2、不需要重新更新cache。
感谢你耐心的看到这里ღ( ´・ᴗ・` )比心,如有哪里有错误请踢一脚作者o(╥﹏╥)o!
给个三连再走嘛~