【Linux】线程概念和控制
目录
线程概念
1、进程的重新理解
进程:分配资源的基本单位,一提到进程,一定是给其分配资源,比如内存,比如CPU
之前说的进程是一个struct和代码和数据,这个是特殊情况;更加普适的情况是一个进程其实包含多个线程,每个线程去处理一部分代码。此时一个进程内部,多个线程指向同一块虚拟地址空间。
所有线程共享地址空间。

2、硬件:物理内存->磁盘的映射
通过page去管理物理内存的每个4KB大小的页框

3、页表肯定不是单张,不然就很大
4、虚拟地址:10+10+12
第一个10:找到对应的页表
第二个10:找到该页表内对应的4KB的页框
第三个10:找到该页框内对应的8字节的具体数据,也就是用12位记录页内偏移的地址
进程能拿到的虚拟地址空间越多,其得到的资源也越多

为什么需要虚拟地址,直接用物理地址不好吗?
答:我们希望操作系统提供给⽤⼾的空间必须是连续的,但是物理内存最好不要连续。
5、线程深层次的理解
创建一个线程比创建一个进程代价小的多,因为创建线程的时候资源已经划分好了,只需要创建对应的pcb就行了。
线程更轻量化。
一般有几个CPU就创建几个线程。

6、线程周边
为啥线程切换更简单?只是因为不用保存CR3寄存器以及不用切换页表吗?这是一个原因,但更重要的是缓存命中,一旦切换进程,那么此时上下文也被切换,缓存中的内容全部要被替换,那么此时访问内存效率就会很低。但要是线程切换,不会全部替换缓存的内容,所以访存的开销不大。
这里的上下文意思是,当把内存一条数据拿到CPU,OS就会把这一条数据上下相关的数据都拿到cache缓存中,以便后续访问。所以一旦进程切换后,这个缓存中所有的上下文数据也都会被替换掉,导致不命中。

线程控制
1、一个进程,两个线程,其中一个崩了,那么整个进程就被终止了,所以线程健壮性不好

2、用户只知道线程,但是Linux只有创建微进程的接口,因此二者不一,那么直接在用户与系统之间实现一个软件层,也就是pthread库

C++11的多线程,本质也是封装了pthread库

3、pthread_create创建线程以及pthread_join等待线程
lwp不是线程id,线程有自己的线程id的,可用pthread_self方法获取当前线程的id

4、pthread_join
在main里等待的目标线程,如果异常了,包括main线程,所以,join异常,没有意义,看也看不到!join都是基于:线程健康跑完的情况,不需要处理异常信号,异常信号,是进程要处理的话题!
pthread_join:拿到的返回值,就是线程退出设定的返回值

5、给线程传递的参数和返回值,可以是任意类型(包括对象)
6、线程终止的问题:
(1)新线程里,进行return就是线程终止。(用的最多)
(2)线程不能exit()终止,因为exit是终止进程的!
(3)pthread_exit()
(4)pthread_cancel();在main里取消新线程,那么目标线程的退出码就是-1

7、注意:本质线程是进程的一部分
(1)不能再线程里出现异常
(2)不能再线程里用exit
8、如果主线程不想再关心新线程,而是当新线程结束时,让它自己释放?设置新线程为分离状态。
类似于进程里面,父进程提前把SIGCHLD信号的处理方式设为SIG_IGN(忽略)。内核会知道:“这个父进程不想管子进程的退出,我来自动回收它的资源”。此时子进程退出后,内核会直接清理它的资源,不会变成僵尸进程,父进程也就不用调用wait了。
技术层面:线程默认是需要被等待的,joinable,如果不想让主进程等待新线程,想让新线程结束后,自己退出,设置为分离状态(!joinable or detach)。
理解层面:线程分离,主分离新,新把自己分离。分离线程,依旧在进程的地址空间中,进程的所有资源,被分离的线程,依旧可以访问,可以操作。主不等待新线程。
主线程分离新线程,pthread_detach,分离后,不需要join,主线程不能再pthread_join新线程了,会出错,新线程会自动释放资源。


9、pthread_create
①在库里创建一个线程tcb
②内核底层也会用clone方法真正创建一个线程,具体执行的方法会映射到库里的方法
10、mmap
①把这段内存映射到进程的虚拟地址空间
②两个进程的虚拟地址空间都同时映射到同一个内存空间,也就是共享内存
③磁盘空间映射到物理内存,对于进程来说,就不用文件描述符访问文件了,直接用虚拟地址就可以访问物理内存里面的文件了

11、线程的局部存储,只有当前线程自己能访问

更多推荐




所有评论(0)