一:进程
1.进程状态转换
进程包括新建、就绪、阻塞、运行以及退出状态。
当有一个请求需求时,进程可能会被创建。当一个处于运行状态的进程需要等待某个事件或者资源的发生时,它就从运行态转换到阻塞态,当事件或者资源到达,那么就会转为就绪态,当操作系统调度该就绪进程,为其分配时间片的时候,该进程就从就绪态转为运行态。当运行态的进程时间片用尽或者被其他更高优先级的进程抢占,那么该进程就从运行态转为就绪态。此外,当内存不够时,或者为了提高系统性能,常常会将处于阻塞态的位于内存中的进程的一部分信息从内存移到磁盘上,以腾出更多的内存空间。此时被从内存调入磁盘的进程就处于挂起状态。
2.进程创建
(1)给新进程分配一个唯一的进程标识符。在主进程表中增加一项,其中每一项都表示一个进程的指针。
(2)给进程分配空间:也就是分配进程映像中的所有元素,包括程序、数据、栈和属性。给进程控制块分配空间。
(3)初始化进程控制块。
(4)设置正确的连接:比如将进程放置到某个就绪或者挂起链表中。
(5)创建和扩展其他数据结构:比如操作系统可能为每个进程保存一个记账文件,可用于编制账单或者用于进行性能评估。
3.进程切换
(1)何时切换:在操作系统发生中断、陷阱或者系统调用的时候会发生进程的状态切换。最常见的就是系统中断,系统中断分为中断和陷阱。中断就是指与本进程无关,是由于外部事件的触发导致中断产生,从而引起本进程状态切换。常见的普通中断有时钟中断(时间片失效),IO中断(操作系统发生了IO活动),内存失效(处理器访问了一个虚拟内存地址,但这个地址不在内存中,必须进行段或者页的调入工作)。陷阱就是指本进程在执行的过程中发生了错误或者异常,当错误或者异常致命,那么就从运行态转换为退出态。系统调用是说在进程执行系统调用,这个调用会导致转移到作为操作系统代码一部分的一个例程上执行。通常,使用系统调用会导致把用户进程置为阻塞态。
(2)进程切换的步骤:
1.保存处理器上下文环境,包括程序计数器和其他寄存器。
2.更新当前处于运行态进程的进程控制块,包括将进程的状态改变到另一状态。还必须更新其他相关域,包括离开运行态的原因和记账信息。
3.将进程的进程控制块移到相应的队列。
4.选择另一个进程执行。
5.更新所选择进程的进程控制块,包括将进程的状态改为运行态。
6.更新内存管理的数据结构,这取决于如何管理地址转换。
7.恢复处理器在被选择的进程最近一次切换出运行状态时的上下文环境,这可以通过载入程序计数器和其他寄存器以前的值来实现。
二:线程
1.线程同步
一个进程中的所有线程共享同一个地址空间和诸如打开的文件之类的其他资源,一个线程对资源的任何修改都会影响同一个进程中其他线程的环境,因此,需要同步各种线程的活动,以便它们互不干涉且不破坏数据结构。
2.用户级线程和内核级线程
用户级线程:有关线程管理的所有工作都由应用程序完成,内核意识不到线程的存在,任何应用程序都可以通过使用线程库被设计成多线程程序,线程库用于用户级线程管理的例程包,包含创建和销毁线程的代码、在线程之间传递消息和数据的代码、调度线程执行的代码、以及保存和恢复线程上下文的代码。
内核级线程:有关线程管理的所有工作都由内核完成,应用程序部分没有进行线程管理的代码,只有一个到内核线程设施的应用程序编程接口。内核为进程及其内部的每个线程维护上下文信息。调度是由内核基于线程完成的。如果内核中的一个线程被阻塞,内核可以调度同一进程中的另一个线程。并且可以把同一个进程中的多个线程调度到多个处理器中。但是在把控制从一个线程传送到同一进程中的另一个线程时,需要内核的状态切换。
3.线程阻塞
3.1 用户级
当用户级线程执行一个系统调用时,不仅这个线程会被阻塞,进程中的所有线程都会被阻塞。其次,在纯粹的用户级线程策略中,一个多线程应用程序不能利用多处理技术。内核一次只能把一个进程分配给一个处理器,因此一次进程中只有一个线程可以执行,事实上,在一个进程中,我们相当于实现了应用程序级别的多道程序。尽管多道程序会使得应用程序的速度明显提高,但是同时执行部分代码更会使得某些应用程序受益。
当然,我们可以采用把应用程序写成一个多进程程序而非多线程程序来解决这两个问题。但进程之间切换消耗开销比较大。除此之外,还有一个解决方法称为jacketing技术。它的目标是把一个产生阻塞的系统调用转化成一个非阻塞的系统调用。例如,不是直接调用一个系统IO例程,而是让线程调用一个应用级的IO jacking例程,该例程就是用来检测并确定IO设备是否在忙,如果忙,该线程进入阻塞态并将控制权传送给另外一个线程,当这个线程后来重新获得控制时,jacket例程会再次检查IO设备。
3.2 混合方法
混合采用用户级线程和内核级线程的方式,线程创建、调度和同步在应用程序中,只有多个用户级线程被映射到一些内核级线程上,以便开发人员调整,以达到最佳效果。同一个应用程序中的多个线程可以在多个处理器上并行运行,某个会引起阻塞的系统调用不会阻塞整个进程。