finish chp11.md, conclusion on process and thread, part one.

This commit is contained in:
Shine wOng
2019-09-11 16:44:56 +08:00
parent ddb5ce5385
commit 5e214126ab
5 changed files with 75 additions and 5 deletions

View File

@@ -17,7 +17,7 @@
从上面的讨论中,已经可以总结出进程和程序的区别了:
+ 首先,程序是静态的,进程是动态的。程序其实静态的可执行文件,是可以永久保存的;但是进程由于其运行的性质,不可避免地具有各个生命周期,比如创建,运行,等待,退出等,它是动态变化的,有始有终的。由此也可以得出结论,同一个程序的多次执行过程是对应了不同的进程。
+ 首先,程序是静态的,进程是动态的。程序其实静态的可执行文件,是可以永久保存的;但是进程由于其运行的性质,不可避免地具有各个生命周期,比如创建,运行,等待,退出等,它是动态变化的,有始有终的。由此也可以得出结论,同一个程序的多次执行过程是对应了不同的进程。
+ 其次就是两者的组成成分不同,进程是包含了程序的,除此以外进程还含有数据,状态信息等。
现在,我们可以给出一个更加严谨的进程的定义了:
@@ -29,7 +29,7 @@
+ 动态性
+ 并发性:进程就是为了多任务并发运行而产生的
+ 独立性:指不同的进程,它们的工作互不影响
+ 制约性:操作系统的资源是有限的,所有进程共享这些有限的资源,不可避免会因为资源的分配或者进程间同步而产生制约
+ 制约性:操作系统的资源是有限的,所有进程共享这些有限的资源,不可避免会因为资源的分配或者进程间同步而产生制约
## 进程控制块
@@ -37,13 +37,13 @@
这就好比你在烟花巷开了一家青楼,对于每一个客人,有的要先喝个酒,你得给他分配一瓶酒;有的客人直接带姑娘上楼了,那你得知道它带的是哪个姑娘,别的客人请求这个姑娘的时候他们就只能等着;然后这个客人带着这个姑娘,你得知道他什么时候完事儿了,你总不能让他就把姑娘给你带走了,你得把姑娘进行回收,然后再把姑娘分配给等着的那些客人。
进程管理也是出于同样的目的。进程管理其实只在意资源的分配和回收为了管理资源,还需要同时管理进程的状态,这样操作系统才知道什么时候应该分配资源,什么时候又应该回收资源。
进程管理也是出于同样的目的。进程管理其实只在意资源的分配和回收。但是为了管理资源,还需要同时管理进程的状态,这样操作系统才知道什么时候应该分配资源,什么时候又应该回收资源。
进程控制块(PCB, Process Control Block)就是操作系统用于完成进程管理的数据结构。操作系统用PCB来描述进程的基本情况以及运行变化的过程每加入一个进程操作系统就为它管理一个PCB一旦进程退出运行就随即销毁它的PCB因此PCB是进程存在的唯一标志。
> 进程控制块的具体结构是什么?
进程控制块的功能其实就是完成对一个进程的管理工作。为了完成这样的管理工作,进程控制块至少要保存:
进程控制块的功能其实就是完成对一个进程的管理工作,它的结构必然是与它要完成的功能相适应的。为了完成这样的管理工作,进程控制块至少要保存:
+ 进程的状态信息:比如进程如果刚被创建,就需要为它分配必要的资源。如果它执行完成退出了,那么需要去回收分配给它的资源。
+ 进程的资源占用信息。进程当前占用了哪些资源,比如占用了哪些内存资源,方便在退出的时候回收到操作系统。
@@ -84,7 +84,7 @@
处于挂起状态的进程映像在磁盘上。将挂起状态与三状态进程模型综合一下,就产生了等待挂起状态和就绪挂起状态,因为显然在运行态的进程必须驻留在内存中,不可能换出到外存。
等待挂起状态是指进程在外存中,并且等待某个时间出现的情况;就绪挂起状态是指进程在外存中,但是一旦进入内存,就可以运行。挂起进程模型的切换和相关的时间如下图所示:
等待挂起状态是指进程在外存中,并且等待某个事件出现的情况;就绪挂起状态是指进程在外存中,但是一旦进入内存,就可以运行。挂起进程模型的切换和相关的时间如下图所示:
![suspend_proc](images/suspend_proc.png)
@@ -103,4 +103,74 @@
![status_queue](images/status_queue.png)
## 线程的概念
> 为什么需要引入线程的概念?
设想一种场景。现在我们有一个MP3播放器的应用程序该应用程序主要有三个核心功能模块即从MP3音频文件中读取数据将读取的数据解压缩将解压缩后的音频数据播放出来。应该如何实现这个应用程序呢
这里我们主要考虑的指标是音频文件播放是否流畅、连贯。为此,就需要设计的应用程序可以及时将刚读出来的压缩数据解压缩,并且播放出来。一种简明的设计思路如下图所示:
![mp3_version_1](images/map_version1.png)
在该设计思路中我们将读取数据解压缩播放文件依次执行。但是不难看出这种实现存在很致命的缺陷各个模块之间不能并行进行。可以看到这里读取压缩音频文件涉及到I/O操作解压缩是CPU密集型操作因此这两个模块在理论上是可以并发执行的即在将压缩文件读取出来的同时CPU可以对这些数据进行解压缩这样可以大幅度提高资源的利用效率。此外按照我们的设想在播放时应该也可以同时进行读文件和解压的操作在这种实现方式都却不能做到。在这种实现下为了播放音频文件连贯必须一次性将全部音频文件读出并且解压缩最后才能播放漫长的等待时间非常影响用户体验。
为了将各个操作并行地推进我们很自然地联想到将各个核心模块全都加载到一个进程中即为了运行这个MP3播放器软件我们同时需要三个进程这种设计思路如下图所示
![mp3_version_2](images/map_version2.png)
这种方法的确解决并行的问题,但是却引入了新的问题——可以看到,这里的三个进程之间需要共享数据,前一个进程的输出,是下一个进程的输入,因此需要解决在进程之间通信以及共享数据的问题。此外,进程的创建以及进程之间的切换是需要相当的开销的,这种实现方式无疑增加了开销。
我们的梦想呢,是有这样一种结构,它可以像进程一样进行切换,从而实现并行性;另一方面,数个这样的结构又可以共享数据,并且它们之间的切换的开销要足够的小。这样的梦想中的结构,就是线程。
> 线程的概念
为了解决上面的问题可以在进程内部增加一种实体这些实体之间都共享进程的资源而CPU又可以在这些实体之间切换这种实体就是线程。
线程是进程的一部分描述指令流执行状态。它是进程中的指令执行流的最小单元是CPU调度的基本单位。引入了线程以后CPU的调度就不再以进程为单位了从而进程就退化成为了资源分配的单位而进程中的线程共享分配给进程的资源并且都可以独立地描述其中指令流的执行状态。
那么,线程之间切换的开销的确小于进程切换吗?我们可以做一个考虑。首先由于线程本身不占有资源,在创建线程时不需要像进程一样分配资源,因此时间开销要小于进程的创建;也由于同样的原因,线程的退出需要的时间也比进程短,因为没有资源的回收;此外,同一进程的不同线程之间的切换,由于它们是共享数据,不需要进行用户空间、内核堆栈等的切换,只需要保存和恢复上下文信息就足够了,需要的时间也的确比进程切换要短。因此可以看到,线程相比于进程,能减少并发执行的时间和空间开销。
关于进程和线程的关系可以用一句话总结即进程拥有一个完整的资源平台而线程只独享指令流执行的必要资源如寄存器和栈。进程是资源分配单位线程是CPU调度单位。
为了实现在实际系统中实现线程,可以有几种方案,即用户线程,内核线程以及轻量级进程。
### 用户线程
用户线程的思路其实非常简明:只是在用户空间实现线程,进程的线程对于操作系统是不可见的。这样,进程仍然是操作系统资源分配和调度的基本单位。用户线程的示意图如下图所示:
![user_thread](images/user_thread.png)
仍然拿上面的MP3播放器举个例子我可以在编写程序的时候手动为它划分三个核心功能模块。在操作系统调度这个播放器进程运行的时候在进程内部也运行一个调度程序来选择某一个核心模块实际运行。
通过上面的实例可以看到用户线程的特征:
+ 首先是非常灵活,因为是在进程的内部提供线程的调度算法,因此调度算法的设计可以更有针对性,不同的进程可以拥有不同的调度算法。
+ 线程对操作系统是不可见的线程控制块TCB需要进程本身来维护。
+ 线程之间的切换很快,直接在进程运行中就可以切换,不需要用户态/内核态的切换。
但是用户线程还是存在不足。编程困难都不算什么不足毕竟程序员是干什么吃的最大的不足是一个线程阻塞的时候其他线程也都阻塞了。因为操作系统看不到用户线程一旦发生阻塞操作系统就立即将CPU的控制权转交给其他进程了对于MP3播放器这种应用还是不能实现I/O和解压缩的CPU操作并行。
除此以外操作系统调度进程是以进程为单位分配CPU时间一个进程的所有线程共享这部分CPU时间每个线程的时间片较小。
### 内核线程
内核线程可以解决上面提到的用户线程的不足。内核线程就是指,线程对于操作系统是可见的,由操作系统来管理线程。内核线程的示意图所下图所示:
![kern_thread](images/kern_thread.png)
由于是由内核来同时维护PCB和TCB一个进程的线程被阻塞并不会影响该进程的其他线程这样音频文件的读取和解压缩就可以并行进行了因此在实现了内核线程的操作系统上我们的MP3播放器终于可以正常地并行地工作了。此外由于操作系统调度的基本单位成了线程不会出现上面提到的线程的时间片太短的情况。
但是相对于用户线程,内核线程也具有一定的缺陷。一方面,内核线程的创建、切换和退出的开销比较大,因为这些操作是通过系统调用实现的,需要进行用户态/内核态的切换。此外,由操作系统统一给出线程的调度算法,不如用户线程那么灵活。
为了综合用户线程和内核线程的优点,提出了轻量级进程的概念。
### 轻量级进程(LightWeight Process)
轻量级进程是内核支持的用户线程。一个进程可有一个或多个轻量级进程,每个轻权进程由一个单独的内核线程来支持。
轻量级进程的实现综合了内核线程和用户线程。具体说来,对于每一个进程,内核中都管理了一定量的它的内核线程。但是在用户进程的内部,同时还存在着一定的用户线程。操作系统调度的基本单位仍然是内核线程,但是可以将用户线程和内核线程进行绑定,以在一定程度上改变这种调度关系,实现用户线程那种灵活的线程调度。轻量级进程的示意图如下图所示:
![lightweight_proc](images/lightweight_proc.png)
可以看到,在轻量级进程中,用户线程和内核线程是多对多的关系。除此以外,还有用户线程对内核线程是一对一或者多对一的关系的情况,分别对应了内核线程和用户线程。

Binary file not shown.

After

Width:  |  Height:  |  Size: 65 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 35 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 34 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 48 KiB