Linux多线程(一):什么是线程?

一、前言

什么是线程?操作系统书籍上可能会给你这样的解释与定义:

  • 线程是在进程内部运行的执行流
  • 线程比进程的执行力度更细,线程的调度成本更低
  • 线程是CPU调度的基本单位

 显然这些话放诸四海皆准,对于任何的操作系统都是适用的。讲的太过于概括,真是“听君一席话,如听一席话”,对于线程还是没有一个明晰的认识。但在这篇博客里,我们不谈什么高大上的东西,我将用最浅显的语言让大家理解Linux下的线程是什么样的,以及我们应该如何创建、控制多线程

二、什么是线程?

 在学习线程之前,大家想必都学习过进程。在进程中,我们可以使用fork()函数来创建子进程(如下)。父子进程间代码和数据是共享的(不对数据做修改的话),我们通过if判断语句让父子进程分别执行不同的代码,因此我们可以初步形成以下认识:可以对不同的执行流划分同一块空间,使其执行不同的代码

int main()
{
    
    
    pid_t pid = fork();
    if(pid == 0){
    
    
        // 子进程代码
    }
   else {
    
    
        // 父进程代码
    }
}

 基于这样的认识,我们不禁思考,能否对一个进程的进程地址空间进行划分呢?线程本质上就是 “轻量级进程” ,即只执行一个进程的部分代码,占用部分的进程地址空间,占用部分的物理内存。

三、线程是如何实现的?

 不同于Windows操作系统,Linux并没有真正意义上的线程。Linux中线程本质上复用的就是进程的数据结构——我们同样创建 task_struct,但是不独立分配进程地址空间和页表,因此各个线程看到同一份进程地址空间,但是只执行部分代码,使用部分物理空间。
 CPU调度的基本单位就是 PCB(Linux中就是task_struct) ,当CPU调度进程的时候,看到的是一个PCB;当CPU调度线程的时候,看到的仍然是一个PCB,并且使用的是同一块进程地址空间。从CPU的角度看,这有区别吗?这没有任何区别,在Linux中,没有线程与进程的区别,只有执行流的区别。只不过基于我们上面对于“轻量级进程”的阐述,你不难理解,线程的 task_struct 背后挂靠的进程地址空间和页表,必然是曾经进程地址空间和页表的一小部分。
 CPU可以轮流调度各个 task_struct, 由此让原本串行的代码得以在同一时间段内同时得以推进,这种解决方案就叫做线程。
在这里插入图片描述
 Linux复用PCB(process control block)来模拟实现TCB(thread control block),因此Linux中TCB就是PCB,这是一种非常优雅的设计方案,这里给大家列举几个优势:

  • 不用单独设计TCB
  • 不用维护TCB和PCB之间的关系
  • 不用单独编写TCB的调度算法
  • ……

我们重新认识一下什么是进程什么是线程:

  • 内核的角度看,进程就是承担分配系统资源的基本实体
  • 线程是调度的基本单位

四、基本概念梳理

我们再来理解之前提到的课本上对于线程解释与分析:

  1. 线程是在进程内部运行的执行流
    【理解】:因为线程是在进程的进程地址空间内部运行的,所以是在进程内部执行的
  2. 线程比进程的执行力度更细
    【理解】:因为线程只是执行进程的部分代码,访问进程的部分数据
  3. 线程的调度成本更低
    【理解】:线程间共用同一套进程地址空间,因此线程切换时,不需要切换进程地址空间和页表,只需要切换上下文数据即可
  4. 线程是CPU调度的基本单位
    【理解】:CPU在调度的时候只看PCB。一个PCB就对应着一个线程

五、后记

 线程有什么优点和缺点呢?光谈理论想必大家也难以理解,之后会逐步给大家呈现。如何创建线程、使用线程呢会在下篇博客里为大家深度剖析

猜你喜欢

转载自blog.csdn.net/whc18858/article/details/128208886
今日推荐