1、进程的分身术:线程
线程是什么?进程是运转的程序。是为了在CPU上实现多道变成而发明的一个概念。但是进程在一个时间只能干一个事情。如果向同时干两件事,我们自然想到创说中的分身术。
进程可以办到,办法就是进程。线程就是我们为了让一个进程同时干多件事情,而发明的分身术。
既然线程就是进程的分身,那么每一个线程在本质上1是一致的,即同样同游程序文本。但由于是1分身,自然有不同地方1,这就是线程执行时的上下文不一致。事实上,我们说线程是进程里面的一个执行上下文或者执行序列。显然,一个进程可以同时拥有多个执行序列。这就像舞台,舞台上可以有多个演员同时登场,而这些演员和舞台就构成了一出戏。类比进程核1线程。每个演员是1一个线程,舞台是地址空间,这个同一地址空间里面的所有线程就构成了进程。
在线程模式下,一个进程1至少有一个线程,但也可以由多个线程。
将进程分解为线程还可以有效地利用多处理器和多核计算机。在没有线程的情况下,增加一个处理器并不能提高一个进程的执行速度。但如果分解为多个线程,则可以让不同的线程同时1运转在不同的处理器上,从而提高了进程的执行速度。
例如我们使用1word时,实际上打开了多个线程,这些线程一个负责显示,一个接受输入,一个定时存盘,这些进程一起运转才能让我们感觉到,输入和显示同时发生,而不用输入一些字符,等待一会儿才显示到屏幕上。在我们不经意间,文字处理软件还能自动存盘。
2、线程管理:
有进城后,要管理进程。那么有线程后,也要进行管理。维持线程的各种信息。这些信息包含了线程的各种关键资料。存放这些信息的数据结构称为线程控制表或线程控制块。那么线程控制块里面到底包含哪些信息?
我们说过线程共享一个进程空间,因此,许多资源是共享的。这些共享的资源显然不需要存放在线程控制模块里面,而是存放在线程控制块。但是由于线程是不同的执行序列,总会有些不能共享的资源。
3、线程模型的实现:
线程模型在进程基础上提供第二次并发。由于线程之间的共享远比进程之间的共享丰富,因此其在需要高度共享的环境1下发挥着重要作用。单线程这个模型如何实现?
与进程一样,线程本身叶对应着某种物理现实,也需要存储和调度。在存储上,由于线程依附于进程而存在,其存储解决方案无需额外设计,而是直接赋予进程的存储方案。
由于线程是在进程基础上产生的概念(进程里面的一个执行序列),其调度可以由进程负责。当然,我们也可以将线程的调度将给操作系统。而这两种不同的调度推手就形成了线程的两种实现:用户态和内核态实现。而进程自己管理就是用户态线程的实现,由操作系统管理就是内核态线程的实现。用户态和内核态的判断以线程表所处的位置为依据:位于内核叫内核态实现。用户态和内核态的判断以线程表所处的位置为依据:位于内核叫内核态实现,位于用户层就叫用户态实现。
(1)内核态线程的实现:
线程是进程的分身,是进程的不同执行序列。既然每一个线程是不同的执行序列,则说明线程应该是CPU调度的基本单位。我们知道CPU调度是由操作系统实现的。因此,让操作系统来管理线程似乎是天经地义的事情。
那么操作系统是怎么来管理线程那?与管理进程一样,操作系统要管理线程,就要维护线程的各种资料,即将线程1控制块存放在操作系统内核空间。这样操作系统内核就同时保有进程控制块和进程控制块。
由操作系统来管理线程有很多好处,最重要的好处是用户编程简单。因为现成的复杂性由操作系统承担,用户程序员在编程时无需管理线程的调度。即无需担心线程什么时候会执行,什么时候会挂起。另外一个重要的好处是,如果一个线程执行阻塞操作,操作系统就可以从容的调度另外一个线程执行。因为操作系统能监控所有的线程。
(2)用户态线程的实现:
就是用户自己做线程的切换,自己管理线程的信息,而操作系统无需知道线程的存在。
那么1在用户态如何进行线程调度?那就是用户自己写一个执行系统,做调度器,即除了正常执行任务之外,还有一个专门负责线程调度的线程。由于大家都在用户态下执行,谁也不比谁占优势,要想取得CPU控制权只能靠大家自愿合作。一个线程在执行完一段时间之后1主动把资源释放给别人使用,而在内核态下则无需如此。
那么用户态有什么优点?
(1)灵活性,os无需知道线程的存在,在任何操作系统上都能使用;
(2)线程切换快,切换在用户态进行,无需陷入到内核态。最后是不用修改操作系统,实现容易。
缺点:程序变得诡异,用户态线程需要相互合作才能运转。这样,我们再写程序时,必须仔细斟酌在什么时候让出CPU给别的线程使用。
3、现代操作系统线程实现1模型:
先到操作系统将用户态和内核态线程模型相结合。用户态1的执行系统负责进程内部线程在非阻塞时的切换。内核态的操作系统负责阻塞线程的切换。即我们同时实现内核态和用户态线程管理。其中内核态线程数量较少,而用户态线程数量较多。每个内核态线程可以服务一个或多个用户态线程。用户态线程被多路复用到内核态线程上。
例如:某个进程有5个线程,我们可以将5个线程分成2组,一组3个线程,另外一组2个线程。每一组线程使用一个内核线程。这样,该进程即将使用两个内核线程。如果一个线程阻塞,则与其同属于一族的线程皆被阻塞,但是另外一组线程却可以继续执行。
这样,我们再分配线程时,我们可以将需要执行阻塞操作的线程设为内核态线程,而不会执行阻塞操作的线程设为用户态线程。
4、多线程的关系:
推出线程模型目的就是实现进程级并发。因为在一个进程中通常会出现多个线程,否则,我们也没有必要搞什么线程了。就像看舞台剧,如果从头到尾就一个人在演,我们就会觉得无聊。
但共享一个舞台就会麻烦。就像人们共享资源时就会发生纷争。线程1在共享地址空间过程中也会产生矛盾。这些矛盾:有如下:
(1)线程之间如何通信
(2)线程之间如何同步
而上述两个问题在进程层面也同样存在。从一个更高的层面上来看,不同的进程也共享着一个巨大的空间,这个空间就是整个计算机。因此进程之间也会存在矛盾,这些矛盾也体现在如何通信(沟通)和如何同步(协调)上。
5、线程间同步
引入进程之后,也引发了一个巨大的问题,即多线程程序的执行结果有可能是不确定的。而不确定则是我们1人类非常反感的东西。那么如何在保持线程这个概念的同时,消除其执行结果的不确定性?答案就是线程的同步。
1、线程同步的目的:
就是不管线程之间如何穿插,其运行结果都是正确的。或者说,要保证多线程执行下结果的正确性(确定性)而在达到这个目标的同时,要保持对线程执行的限制缺少越好。
除此之外,线程同步的另外一个目的涉及执行效率。除了前面说过的多线程执行的结果是不确定的之外,其执行效率也是不确定的。比如在某段时间AA线程执行了3条指令,BB线程执行了5条指令。 线程a比线程b多执行了指令这不是关键。关键是到底线程 A是否比线程B执行的多,或者多多少》等皆是不确定的。如果我们想要确定就需要线程同步。
线程同步:让所有线程按照一定的规则执行,使得其正确性和效率都有迹可循。线程同步的手段就是对线程之间的穿插进行控制。