【内卷套餐】Linux线程概念和创建

线程的基础概念

  • 线程是进程的执行分支,线程的粒度是比进程更细的
  • 在一个程序里的一个执行路线就叫做线程(thread)。更准确的定义是:线程是“一个进程内部的控制序列”
  • 一切进程至少都有一个执行线程
  • 线程在进程内部运行,本质是在进程地址空间内运行
  • 在Linux系统中,在CPU眼中,看到的PCB都要比传统的进程更加轻量化
  • 透过进程虚拟地址空间,可以看到进程的大部分资源,将进程资源合理分配给每个执行流,就形成了线程执行流
  • 本来一个进程只有一个PCB的时候,代码是串行的(一股执行流),现在我有多个PCB了,并且把进程地址空间中的用户区域也被分成相应的PCB数量了,如果我的CPU是多核的,那么我就可以有多股执行流了,我进程里的代码就可以并行执行了
  • 以前是一个进程一个PCB,现在是一个进程多个PCB,并且该进程所创建的进程地址空间中的代码区被分成多个区
  • 创建新"进程”的时候,我只创建PCB,但是我不创建进程他们各自的地址空间了,我把他们PCB中所要指向的地址空间,指向之前创建的某个进程的进程地址空间
  • 从内核来重新理解进程:承担分配系统资源的基本实体。为了承担系统资源,操作系统为进程创建了大批数据结构和大批的内存块以承载该进程的代码和数据
  • CPU看到的永远都是一个个独立的task_struct,而不在乎你是谁,你是哪个PCB,和哪个进程地址空间相对应
  • 线程:是调度的基本单位,线程是进程内部的执行流。(线程在进程的地址空间内运,所有的线程,用的是同一个进程的地址空间)
  • 进程与线程的比例关系可以理解为:

       *进程 :线程 == 1 :n;(n可以为1,此时为单线程)
    

Linux中没有真正的线程,它中的线程是用进程模拟的!Linux在设计的时候,没有为多线程设计数据结构,但是如果设计了,就会复杂,复杂,就会失去高效,而Linux是高效的爹;所以设计者用进程模拟实现了线程,而PCB(task_struct)还是要被看成是进程控制块,只不过具体看它是单执行流的进程控制块,还是多执行流的进程控制块~
对于单执行流的进程而言,每一个PCB背后挂靠的都是一个进程的进程地址空间,而对于多执行流的进程,其PCBs(这里加s了,复数)背后挂靠的,都是一个进程地址空间的一部分(多个PCB共享一个进程地址空间)。所以Linux中的所有进程,都被称为轻量级进程,最重也就重到一个完整的单执行流进程。

多线程概念图 在这里插入图片描述

线程的优点

  • 创建一个新线程的代价要比创建一个新进程小得多
  • 与进程之间的切换相比,线程之间的切换需要操作系统做的工作要少很多
  • 线程占用的资源要比进程少很多
  • 能充分利用多处理器的可并行数量
  • 在等待慢速I/O操作结束的同时,程序可执行其他的计算任务
  • 计算密集型应用,为了能在多处理器系统上运行,将计算分解到多个线程中实现
  • I/O密集型应用,为了提高性能,将I/O操作重叠。线程可以同时等待不同的I/O操作。

线程的缺点

  • 性能损失

一个很少被外部事件阻塞的计算密集型线程往往无法与共它线程共享同一个处理器。如果计算密集型
线程的数量比可用的处理器多,那么可能会有较大的性能损失,这里的性能损失指的是增加了额外的 同步和调度开销,而可用的资源不变。

  • 健壮性降低

编写多线程需要更全面更深入的考虑,在一个多线程程序里,因时间分配上的细微偏差或者因共享了
不该共享的变量而造成不良影响的可能性是很大的,换句话说线程之间是缺乏保护的。

  • 缺乏访问控制

进程是访问控制的基本粒度,在一个线程中调用某些OS函数会对整个进程造成影响。

  • 编程难度提高

编写与调试一个多线程程序比单线程程序困难得多

线程异常

  • 单个线程如果出现除零,野指针问题导致线程崩溃,进程也会随着崩溃
  • 线程是进程的执行分支,线程出异常,就类似进程出异常,进而触发信号机制,终止进程,进程终止,该 进程内的所有线程也就随即退出

线程用途

  • 合理的使用多线程,能提高CPU密集型程序的执行效率
  • 合理的使用多线程,能提高IO密集型程序的用户体验(如生活中我们一边写代码一边下载开发工具,就是 多线程运行的一种表现)

实操创建进程

POSIX线程库
与线程有关的函数构成了一个完整的系列,绝大多数函数的名字都是以“pthread_”打头的
要使用这些函数库,要通过引入头文<pthread.h> 链接这些线程函数库时要使用编译器命令的“-lpthread”选项
int pthread_create(pthread_t *thread, const pthread_attr_t *attr, void * (start_routine)(void), void *arg);
参数 thread:返回线程ID
attr:设置线程的属性, attr为NULL表示使用默认属性
start_routine:是个函数地址,线程启动后要执行的函数
arg:传给线程启动函数的参数
返回值:成功返回0;失败返回错误码

首先我们要引入动态库pthread

在这里插入图片描述

这是Makefile的执行,记得后面要加-pthread

在这里插入图片描述
这是创建线程的代码,主线程和新线程都创建死循环,来证明他们他们同时执行

在这里插入图片描述

实验结果现象

顺便来证明下这两个执行流的PID是相同的:先上结果
在这里插入图片描述在这里插入图片描述
只需要在打印语句加上获取PID即可

在这里插入图片描述
我们再来查看一下OS的状态信息,第一个命令我们可以看到确实就一个进程(7731)其中ps -aL
“L"选项用来查看轻量级进程,图中还有一个标识“LWP” -----light weight process!
在线程视角,操作系统看的ID为LWP,不再是以前简简单单的PID了!PID讲的是进程,LWP讲的是PID里不同的执行流,是线程

进一步讨论"pthrad_t"

在这里插入图片描述这个pthread_t
是一个无符号长整形

在这里插入图片描述编写代码,以地址方式打印,查看下一开始声明的tid和主线程自己的pthread_t值,其中函数pthread_self()可以查看自己的线程ID

上结果
在这里插入图片描述结果表明,tid和新执行流的thread_t类型值一样

思考?为什么thread_t tid 这么像地址?

pthread_ create函数会产生一个线程ID,存放在第一个参数指向的地址中。该线程ID和前面说的线程ID不是一回事。前面讲的线程ID属于进程调度的范畴。因为线程是轻量级进程,是操作系统调度器的最小单位,所以需要 一个数值来唯一表示该线程。

pthread_create函数第一个参数指向一个虚拟内存单元,该内存单元的地址即为新创建线程的线程ID,属于NPTL线程库的范畴。线程库的后续操作,就是根据该线程ID来操作线程的。

线程库NPTL提供了pthread_ self函数,可以获得线程自身的ID: pthread_t pthread_self(void);

pthread_t 到底是什么类型呢?取决于实现。对于Linux目前实现的NPTL实现而言,pthread_t类型的线程ID,本质
就是一个进程地址空间上的一个地址。

在这里插入图片描述

所有的线程信息,是在我们的动态库中被保存起来的,动态库中有一个保存线程结构的数组,每一个thread_t id就对应一个数组元素的起始地址,它负责保管,操作系统负责执行,所以它里面一定有信息去和操作系统的LWP相关联。


线程程序的健壮性不好,只要有一个线程执行崩溃,整个进程就会崩溃

上案例,我写的是系循环噢,但是我在新线程中加入一个➗0错误代码,跑起来的时候,整个进程都被中断了。在这里插入图片描述在这里插入图片描述

线程和进程

  • 进程是资源分配的基本单位
  • 线程是调度的基本单位
  • 线程共享进程数据,但也拥有自己的一部分数据:
  1. 线程ID------------------用户级别的thread_t tid, 和内核级别的LWP
  2. 一组寄存器----------线程的上下文信息(重要)
  3. 栈----------动态共享库里的私有栈(重要)
  4. errno
  5. 信号屏蔽字
  6. 调度优先级

进程所谓共享:

进程的多个线程共享 同一地址空间,因此Text Segment、Data Segment都是共享的,如果定义一个函数,在各线程
中都可以调用,如果定义一个全局变量,在各线程中都可以访问到,除此之外,各线程还共享以下进程资源和环境:
文件描述符表
每种信号的处理方式(SIG_ IGN、SIG_ DFL或者自定义的信号处理函数)
当前工作目录
用户id和组id
在这里插入图片描述

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值