线程
对于多过程的这种形式,仍然会存在问题:
- 过程之间如何通信,共享数据?
- 保护过程的零碎开销较大,如创立过程时,分配资源、建设 PCB;终止过程时,回收资源、撤销 PCB;过程切换时,保留以后过程的状态信息;
那到底如何解决呢?须要有一种新的实体,满足以下个性:
- 实体之间能够并发运行;
- 实体之间共享雷同的地址空间;
这个新的实体,就是 线程(Thread ),线程之间能够并发运行且共享雷同的地址空间。
什么是线程?
线程是过程当中的一条执行流程。
同一个过程内多个线程之间能够共享代码段、数据段、关上的文件等资源,但每个线程都有独立一套的寄存器和栈,这样能够确保线程的控制流是绝对独立的。
线程的长处:
- 一个过程中能够同时存在多个线程;
- 各个线程之间能够并发执行;
- 各个线程之间能够共享地址空间和文件等资源;
线程的毛病:
- 当过程中的一个线程奔溃时,会导致其所属过程的所有线程奔溃。
线程与过程的比拟如下:
- 过程是资源(包含内存、关上的文件等)调配的单位,线程是 CPU 调度的单位;
- 过程领有一个残缺的资源平台,而线程只独享必不可少的资源,如寄存器和栈;
- 线程同样具备就绪、阻塞、执行三种根本状态,同样具备状态之间的转换关系;
- 线程能缩小并发执行的工夫和空间开销;
对于,线程相比过程能缩小开销,体现在:
- 线程的创立工夫比过程快,因为过程在创立的过程中,还须要资源管理信息,比方内存治理信息、文件治理信息,而线程在创立的过程中,不会波及这些资源管理信息,而是共享它们;
- 线程的终止工夫比过程快,因为线程开释的资源相比过程少很多;
- 同一个过程内的线程切换比过程切换快,因为线程具备雷同的地址空间(虚拟内存共享),这意味着同一个过程的线程都具备同一个页表,那么在切换的时候不须要切换页表。而对于过程之间的切换,切换的时候要把页表给切换掉,而页表的切换过程开销是比拟大的;
- 因为同一过程的各线程间共享内存和文件资源,那么在线程之间数据传递的时候,就不须要通过内核了,这就使得线程之间的数据交互效率更高了;
所以,线程比过程不论是工夫效率,还是空间效率都要高。
对于线程和过程,咱们能够这么了解:
- 当过程只有一个线程时,能够认为过程就等于线程;
- 当过程领有多个线程时,这些线程会共享雷同的虚拟内存和全局变量等资源,这些资源在上下文切换时是不须要批改的;
另外,线程也有本人的公有数据,比方栈和寄存器等,这些在上下文切换时也是须要保留的。
这还得看线程是不是属于同一个过程:
- 当两个线程不是属于同一个过程,则切换的过程就跟过程上下文切换一样;
- 当两个线程是属于同一个过程,因为虚拟内存是共享的,所以在切换时,虚拟内存这些资源就放弃不动,只须要切换线程的公有数据、寄存器等不共享的数据;
所以,线程的上下文切换相比过程,开销要小很多。
用户级线程和内核级线程
用户级线程模型
多个用户线程对应同一个内核线程
用户线程的调度是基于用户空间的线程函数库来实现的,用函数库来实现线程。
把 创立线程 、 终止线程 等性能放在了这个 线程库 内,用户就能够通过调用这些函数来实现所须要的性能。线程库,是位于用户空间的,操作系统内核对这个库无所不知,所以从内核的角度看,它还是按失常的形式治理。
线程管制块(_Thread Control Block, TCB_) 也是在库外面来实现的,对于操作系统而言是看不到这个 TCB 的,它只能看到整个过程的 PCB。所以,用户线程的整个线程治理和调度,操作系统是不直接参与的,而是由用户级线程库函数来实现线程的治理,包含线程的创立、终止、同步和调度等。
用户级线程的一个毛病,这些线程只能占用一个核,所以做不到 并行减速 ,而且因为用户线程的 透明性 , 操作系统是不能被动切换线程的 ,换句话讲,如果 A,B 是同一个过程的两个线程的话,A 正在运行的时候,线程 B 想要运行的话,只能期待 A 被动放弃 CPU,也就是被动调用 pthread_yield
函数。”
注:对操作系统来说,用户级线程具备不可见性,也称透明性。
用户级线程做不到像过程那样的 轮转调度 ,尽管不能做到轮转调度,但用户级线程也有本人的益处——能够 为应用程序定制调度算法,毕竟什么时候退出线程你本人说了算。
在操作系统眼里,过程阻塞了,那么整个过程就会进入 阻塞态 ,在阻塞操作完结前,这个过程都无奈失去 CPU 资源。那就相当于, 所有的线程都被阻塞 了。”小白得意的答复。
用户级线程模型的优缺点
用户线程的 长处:
- 每个过程都须要有它公有的线程管制块(TCB)列表,用来跟踪记录它各个线程状态信息(PC、栈指针、寄存器),TCB 由用户级线程库函数来保护,可用于不反对线程技术的操作系统;
- 用户线程的切换也是由线程库函数来实现的,无需用户态与内核态的切换,所以速度特地快;
用户线程的 毛病:
- 因为操作系统不参加线程的调度,如果一个线程发动了零碎调用而阻塞,那过程所蕴含的用户线程都不能执行了。
- 当一个线程开始运行后,除非它被动地交出 CPU 的使用权,否则它所在的过程当中的其余线程无奈运行,因为用户态的线程没法打断以后运行中的线程,它没有这个特权,只有操作系统才有,然而用户线程不是由操作系统治理的。
- 因为工夫片调配给过程,故与其余过程比,在多线程执行时,每个线程失去的工夫片较少,执行会比较慢;
内核级线程模型
一个用户线程对应一个内核线程
许多操作系统都曾经反对内核级线程了。为了实现线程,内核里就须要有用来记录零碎里所有线程的线程表。当须要创立一个新线程的时候,就须要进行一个 零碎调用 ,而后由 操作系统 进行线程表的更新。
操作系统内核如果晓得线程的存在,就能够像调度多个过程一样,把这些线程放在好几个 CPU 外围上,就能做到实际上的 并行 了。
如果线程可见,那么 如果线程 A 阻塞了,与他同属一个过程的线程也不会被阻塞。这是内核级线程的绝对优势。
毛病是,让操作系统进行线程调度,那意味着每次切换线程,就须要「陷入 」内核态,而操作系统从 用户态到内核态 的转变是有开销的,所以说 内核级线程切换的代价要比用户级线程大 。还有很重要的一点——线程表是寄存在操作系统固定的 表格空间 或者 堆栈空间 里,所以内核级线程的数量是无限的,扩展性比不上用户级线程。”
内核级线程模型的优缺点
内核线程的 长处:
- 在一个过程当中,如果某个内核线程发动零碎调用而被阻塞,并不会影响其余内核线程的运行;
- 调配给线程,多线程的过程取得更多的 CPU 运行工夫;
内核线程的 毛病:
- 在反对内核线程的操作系统中,由内核来保护过程和线程的上下文信息,如 PCB 和 TCB;
- 线程的创立、终止和切换都是通过零碎调用的形式来进行,因而对于零碎来说,零碎开销比拟大;
轻量级线程模型
轻量级过程(_Light-weight process,LWP_)是内核反对的用户线程,一个过程可有一个或多个 LWP,每个 LWP 是跟内核线程一对一映射的,也就是 LWP 都是由一个内核线程反对。
另外,LWP 只能由内核治理并像一般过程一样被调度,Linux 内核是反对 LWP 的典型例子。
在大多数零碎中,LWP 与一般过程的区别也在于它只有一个最小的执行上下文和调度程序所需的统计信息。一般来说,一个过程代表程序的一个实例,而 LWP 代表程序的执行线程,因为一个执行线程不像过程那样须要那么多状态信息,所以 LWP 也不带有这样的信息。
在 LWP 之上也是能够应用用户线程的,那么 LWP 与用户线程的对应关系就有三种:
1 : 1
,即一个 LWP 对应 一个用户线程;N : 1
,即一个 LWP 对应多个用户线程;N : N
,即多个 LMP 对应多个用户线程;
接下来针对下面这三种对应关系阐明它们优缺点。先下图的 LWP 模型:
LWP 模型
1 : 1 模式
一个线程对应到一个 LWP 再对应到一个内核线程,如上图的过程 4,属于此模型。
- 长处:实现并行,当一个 LWP 阻塞,不会影响其余 LWP;
- 毛病:每一个用户线程,就产生一个内核线程,创立线程的开销较大。
N : 1 模式
多个用户线程对应一个 LWP 再对应一个内核线程,如上图的过程 2,线程治理是在用户空间实现的,此模式中用户的线程对操作系统不可见。
- 长处:用户线程要开几个都没问题,且上下文切换产生用户空间,切换的效率较高;
- 毛病:一个用户线程如果阻塞了,则整个过程都将会阻塞,另外在多核 CPU 中,是没方法充分利用 CPU 的。
M : N 模式
依据后面的两个模型混搭一起,就造成 M:N
模型,该模型提供了两级管制,首先多个用户线程对应到多个 LWP,LWP 再一一对应到内核线程,如上图的过程 3。
- 长处:综合了前两种长处,大部分的线程上下文产生在用户空间,且多个线程又能够充分利用多核 CPU 的资源。
参考文章
https://mp.weixin.qq.com/s/wn…
https://juejin.im/post/684490…