Linux多线程概念及实现

目录

一.Linux线程基本概念

1.什么是线程

2.页表的映射

3.线程优点

4.线程缺点

5.线程异常

6.线程用途

二.Linux线程vs进程

1.线程和进程

2.进程的多个线程共享资源

3.进程和线程的关系图          

三.Linux线程控制 

1.POSIX线程库

2.线程创建

3.线程等待

4.线程终止

5.线程分离

6.线程ID的深入理解


 

一.Linux线程基本概念

1.什么是线程

  • 在一个程序里的一个执行路线就叫做线程(thread)。更准确的定义是:线程是“一个进程内部的控制序列”。
  • 一切进程至少都有一个执行线程。
  • 线程在进程内部运行,本质是在进程地址空间内运行
  • 在Linux系统中,在CPU眼中,看到的PCB都要比传统的进程更轻量化。
  • 透过进程虚拟地址空间,可以看到进程的大部分资源,将进程资源合理分配给每个执行流,就形成了线程执行流。

                         

(1)进程和线程

  • 创建一个进程需要一堆数据结构, 进程控制块(task_struct)、进程地址空间(mm_struct)以及页表的创建,虚拟地址和物理地址就是通过页表建立映射的。
  • 每个进程都有自己独立的进程地址空间和独立的页表,也就意味着所有进程在运行时本身就具有独立性。
  • 但如果我们在创建“进程”时,只创建task_struct,并要求创建出来的task_struct和父task_struct共享进程地址空间和页表

理解:

  • 其中每一个线程都是当前进程里面的一个执行流,也就是我们常说的“线程是进程内部的一个执行分支”。
  • 同时我们也可以看出,线程在进程内部运行,本质就是线程在进程地址空间内运行,也就是说曾经这个进程申请的所有资源,几乎都是被所有线程共享的。
  • 进程独立和线程共享是相对的
  • 线程是进程内独立的执行分支

 

(2)如何理解之前的进程 

 蓝色部分括起来的整体叫进程

  • 因此,所谓的进程并不是通过task_struct来衡量的,除了task_struct之外,一个进程还要有进程地址空间、文件、信号等等,合起来称之为一个进程。
  • 站在内核角度来理解进程:承担分配系统资源的基本实体,叫做进程。
  • 地址空间只有一个PCB,我就认为他是具有单执行流的进程 ; 地址空间具有多个PCB,我就认为它是具有多个执行流的进程。
  • 以前我们看到100个PCB就认为挂靠的有100个地址空间有页表,代码,数据等等都是不一样的  ;  现在我们看到的1个PCB,这个PCB背后挂靠的可能是和别人共享的地址空间,它只会使用地址空间的一部分.
     

(3)在Linux中,站在CPU的角度,能否识别当前调度的task_struct是进程还是线程?

  •  不能,也不需要了,因为CPU只关心一个一个的独立执行流。无论进程内部只有一个执行流还是有多个执行流,CPU都是以task_struct为单位进行调度的。
  • Linux中所有的PCB(执行流) , 可以看成轻量级进程 ;CPU看到的虽然还是task_struct,但已经比传统的进程要更轻量化了

单执行流:

多执行流: 

(4)Linux下并不存在真正的多线程!而是用进程模拟的! 

  • 操作系统中存在大量的进程,一个进程内又存在一个或多个线程,因此线程的数量一定比进程的数量多,当线程的数量足够多的时候,很明显线程的执行粒度要比进程更细。
  • 如果一款操作系统要支持真的线程,那么就需要对这些线程进行管理。比如说创建线程、终止线程、调度线程、切换线程、给线程分配资源、释放资源以及回收资源等等,所有的这一套相比较进程都需要另起炉灶,搭建一套与进程平行的线程管理模块。
  • 因此,如果要支持真的线程一定会提高设计操作系统的复杂程度。在Linux看来,描述线程的控制块和描述进程的控制块是类似的,因此Linux并没有重新为线程设计数据结构,而是依旧使用task_struct模拟线程,所以我们说Linux中的所有执行流都叫做轻量级进程。
  • 但也有支持真的线程的操作系统,比如Windows操作系统,有TCB,因此Windows操作系统系统的实现逻辑一定比Linux操作系统的实现逻辑要复杂得多。
     

(5)Linux没有真正意义的线程,那么也就绝对没有真正意义上的线程相关的系统调用! 

  • Linux提供了创建轻量级进程的接口,也就是创建进程,共享空间,其中最典型的代表就是vfork函数。 
  • vfork函数的功能就是创建子进程,但是父子共享空间
pid_t vfork(void);

vfork函数的返回值与fork函数的返回值相同:

  • 给父进程返回子进程的PID。
  • 给子进程返回0。

                

(6)关于原生线程库pthread 

  • 在Linux中,站在内核角度没有真正意义上线程相关的接口,但是站在用户角度,当用户想创建一个线程时更期望使用thread_create这样类似的接口,而不是vfork函数,因此系统为用户层提供了原生线程库pthread。
  • 原生线程库实际就是系统编写者对轻量级进程的系统调用进行了封装,通过在用户层模拟实现了一套线程相关的接口。
  • 因此对于我们来讲,在Linux下学习线程实际上就是学习在用户层模拟实现的这一套接口,而并非操作系统的接口。
     

                         

2.页表的映射

(1) 在32位平台下一共有2^32个地址,也就意味着有2^32个地址需要被映射

 

                                 

 (2)每一个表项中除了要有虚拟地址和与其映射的物理地址以外,实际还需要有一些权限相关的信息,比如我们所说的用户级页表和内核级页表,实际就是通过权限进行区分的。

  • 每个应表项中存储一个物理地址和一个虚拟地址就需要8个字节,考虑到还需要包含权限相关的各种信息,这里每一个表项就按10个字节计算。
  • 这里一共有2^32个表项,也就意味着存储这张页表我们需要用2^32 * 10个字节,也就是40GB。而在32位平台下我们的内存可能一共就只有4GB,也就是说我们根本无法存储这样的一张页表。
     

                         

(3)二级页表

①以32位平台为例,其页表的映射过程如下:

  • 选择虚拟地址的前10个比特位在页目录当中进行查找,找到对应的页表。
  • 再选择虚拟地址的10个比特位在对应的页表当中进行查找,找到物理内存中对应页框的起始地址。
  • 最后将虚拟地址中剩下的12个比特位作为偏移量从对应页框的起始地址处向后进行偏移,找到物理内存中某一个对应的字节数据。

                         

②相关说明:

  • 物理内存实际是被划分成一个个4KB大小的页框的,而磁盘上的程序也是被划分成一个个4KB大小的页帧的,当内存和磁盘进行数据交换时也就是以4KB大小为单位进行加载和保存的。
  • 4KB = 2^12个字节,一个页框中有2^12个字节,而访问内存的基本大小是1字节,因此一个页框中就有2^12个地址,于是我们就可以将剩下的12个比特位作为偏移量,从页框的起始地址处开始向后进行偏移,从而找到物理内存中某一个对应字节数据。

                

③补充

  • 这实际上就是我们所谓的二级页表,其中页目录项是一级页表,页表项是二级页表。
  • 每一个表项还是按10字节计算,页目录和页表的表项都是2^10个,因此一个表的大小就是2^10 * 10个字节,也就是10KB。而页目录有2^10个表项也就意味着页表有2^10个,也就是说一级页表有1张,二级页表有2^10张,总共算下来大概就是10MB,内存消耗并不高,因此Linux中实际就是这样映射的。
  • 上面所说的所有映射过程,都是由MMU(MemoryManagementUnit)这个硬件完成的,该硬件是集成在CPU内的。页表是一种软件映射,MMU是一种硬件映射,所以计算机进行虚拟地址到物理地址的转化采用的是软硬件结合的方式。

注意: 在Linux中,32位平台下用的是二级页表,而64位平台下用的是多级页表。

                

(4)修改常量字符串为什么会触发段错误

char* msg = "hello bit\n";
*msg = 'H';

hellobit字符串—定是在内存中存的,但是msg地址用的是虚拟地址,访问hellobit的时候相当于你自己对应的指针变量是在栈区保存的临时变量,地址是虚拟地址,一定要经过页表的映射,字符常量区映射后也一定会找到物理内存  ;  通过msg指针变量访问虚拟地址,经过转换成物理地址,必须有个查表的过程,查找的时候发现映射到的目标区域权限是只R的,你要进行读取没问题,但是你要进行w,mmu内部触发硬件错误,被OS识别到是这个进程导致的错误,立马发信号终止错误

                        

3.线程优点

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值