分类: 信息化
2013-06-04 17:58:01
原文地址:操作系统知识回顾---进程线程模型 作者:fuchao2012
从系统允许多个程序同时进入CPU那一天开始,我们才有了进程,这个对CPU资源的抽象。我们把这种多个程序同时运行在CPU的情况叫做多道程序。其优点不必赘述,举个例子,单一程序设计时,好比公交车上每次只能坐一个人,多道以后,就能坐多个人,有上有下。也是基于这样的设计思路,才有现在的各种貌似高端的技术。多道,跟中断,DMA,SPOOLer一并,被称为计算机操作系统发展史上里程碑一样的创造。
在某个数据集合上,具有独立功能的程序运行过程,叫做进程。英文里有许多叫法(process task job)当然换汤不换药,不同时代的产物罢了。进程的出现,解决了程序并发执行时对系统资源共享的描述问题,同时顺路解决了程序执行时动态特征的描述问题。虽然是抽象出来的概念,但作为程序员,那东西是存在的。
进程控制的目的是为进程完成生命周期指明方向,保驾护航。系统创建了进程,一定要负责到底。从进程创建,撤销,到状态转换中的阻塞,唤醒,挂起,激活,同时还有进程间优先级的控制。这些控制指令都是通过“原语”实现的,这个词不出意外最先是在数据库基础知识中学到的,对滴,不能被打断,打断就抛弃结果。对于系统,没有被打断的可能性。
此处加一个小插曲:进程的创建fork()的执行过程
1.为子进程分配一个空闲进程描述符;
2.赋予子进程唯一标示符pid;
3.以一次一页的方式复制父进程的地址空间(这是Unix的实现方式,linux引入COW技术);
4.子进程获得父进程共享资源的指针;
5.子进程进入就绪态,加入调度队列;
6.子进程返回0,向父进程返回pid。
系统进程vs用户进程,系统进程优先于用户进程
前台进程vs后台进程,前后台进程有优先级的区别,前台往往高于后台
计算密集vsI/O密集,决定了调度策略,是系统设计时讨论的话题
进程的层级结构有树形(unix)和平行结构(windows)
基本状态为三态及转换,如图1
发展一下成为五态模型,加入了创建和撤销两个case,如图2
再复杂一点,加入挂起原语,使得就绪和阻塞有挂起状态,增加了系统调度复杂性,但提高了灵活度,降低调度难度。如图3
linux中包含五种状态,使用宏进行了定义:
TASK_RUNNING对应运行态,TASK_INTERRUPTIBLE可中断态,TASK_UNINTERRUPUTIBLE不可中断态,两种是就绪态中的不同方向
TASK_ZOMBIE僵死状态,对应于阻塞态,TASK_STOPPED停止态,对应于进程的撤销状态。五个状态之间的转换,如图4
就像开车得有方向盘,管理得有管理的可控对象,对于进程来讲,PCB就是进程的方向盘,他是一个专门的数据结构,记录了进程的外部特征,描述了进程的运动过程,标记了进程在整个生命周期中的活动,成为了系统感知进程存在的唯一标识。这个数据结构中包含了三个方面的内容:
进程管理,内存管理,文件管理
看上去就很容易理解了,OS的大部分功能通过进程来实现,所以进程中必须包含实现操作系统功能的“方向盘”。这些内容中,多数是记录了管理相应对象的主指针,以及指向不同管理对象描述块的指针,比如文件管理,指向文件描述块,就是我们常说的FCB等。
在linux系统中,TCB被具体实现为task_struct其中包含了进程调度 pid,信号处理,状态管理,进程队列指针,定时控制,信号量管理,上下文切换,文件系统管理,内存管理等等。这个数据结构能看懂,看完,你的Linux内核分析工作就可以开始了。
内存管理模块会在进程创建的时候分配地址空间,这些空间被进程划分为四大部分:
PCB占用,用户栈空间,私有用户空间(代码),共享空间。其中,PCB占用的部分又划分为PCB号,进程状态,进程控制信息
首先应该明白什么叫做上下文,小学语文的时候,老师就会让我们结合上下文来猜不认识的词的意思,中学英语老师也有这个习惯。现在,这个方式仍然适用,只不过是系统用,他需呀这个上下文信息来猜我们运行到哪里了,进程是什么情况了。我们读完上文,就会记住,然后去读下文,最后综合上下文进行猜词。系统也得这么做。也就是保存上下文信息,分析当前进程运行状态。
上下文信息在系统中指的是用户地址空间内容,多是指正在运行的程序,硬件寄存器内容,多指程序运行状态,该进程相关的核心数据结构最新内容。根据不同的操作对象,我们又把上下文信息分为三种,
用户级上下文:用户地址空间,用户栈信息,程序段信息(代码段,数据段)
系统级上下文:静态信息(PCB,资源使用表)动态信息(核心栈)
寄存器级上下文:PC IP SP ABCD那一些寄存器内部的信息,如果不太懂,可以看组成原理,也可以等我的AT&T汇编指令笔记一文,那里头会讲这些枯燥的符号
再加一个小插曲:中断处理和进程调度的关系,实际上就是当系统发生中断,进程作何反应?
来个原汁原味的图图来说明,英文不好,还是转行吧,别做IT了。如图5
操作系统课程里,陈老师喜欢用字处理软件和web服务器两个例子引入线程,估计是翻译外文书的结果,我也喜欢翻译外文书,估计是找了个翻译专业的媳妇的结果,哈哈哈,说远了。此处也给大家简单介绍一下这两个模型。
1.字处理软件,比较常见的就是word,当然,当今的2013,绝非这么简单。我们抽象出来三个线程,接收键盘输入并显示,自动排版缩进,自动存盘。三个过程都是在word的进程中,他们共享当前所操作的文件,协同处理,当然他们分工不同,也有先后顺序。
2.web服务器,一个web server进程中会包含这么几个进程,网络连接,分派线程,网页处理,网页缓存等。这些线程运行在用户空间,由网络连接请求发起。当然,话又说回来,并非所有的web服务器都得设计成多线程的模型,系统管理用的多了,实际用于工作的资源就会少,平衡这些因素,才能选出合适的设计方案。
基于这两个模型,我们引入线程的概念,对于一个活动的进程,我们想让他同时执行多种功能,但是这几种功能之间通过不同进程的解决方案通信开销太大,调度开销也不小,因此我们应该给出一个比进程更轻量级的实体,他们能够共享的资源更多,通信更方便高效,低耗,线程这玩意就应运而生了。老话说得好,进程是系统最小资源分配单位,线程是系统最小调度单位,线程是轻量级的进程。一语中的。
线程的模型与进程相似,同样包含线程实现功能所需的数据结构,运行时状态等信息,同时包含可读写的所在进程的资源。那么进程与线程的实质上的区别在哪儿呢?
一个线程可以运行在不同进程之间,一个进程可以有多个线程。线程可以有自己的资源,也可以共享进程的资源。本质上的区别,可以从线程的实现机制中说明。
1.用户级线程linux
通过用户程序空间的一组线程库函数完成所有线程的管理。内核并不知到线程的具体运行情况,线程之间的切换和状态转移不需要核心态系统支持,调度过程是基于应用程序,特有的线程过程。具体的实现过程如下:当系统对进程进行调度的时候,进程对其内部的用户级线程进行调度和状态转换,提高进程内部资源的利用率。当进程内部一个线程处于阻塞状态时,可以将其他就绪态的线程运行。但是当线程提出系统调用或者发生中断时,进程也被阻塞。
这么做的优点是:线程切换不必调用系统核心;调度过程是基于用户程序的,可以针对用户程序业务逻辑选择更好的调度算法;用户级线程模型可以运行于任何系统上,只需要有相应的线程库支持。
当然缺点也很明显,当进程内部某一个线程进行系统调用时,整个进程都会被阻塞,这样会影响整体的效率;进程分配到的资源不能够在两个CPU同时运行,换句话说,用户级线程不能支持多核多线程的用户要求。
常见的用户级线程支持库是POSIX线程库,其中包含线程控制的大部分函数接口。
2.核心级线程windows
相对应于用户级线程,就是系统线程。这种线程模型中,所有的线程管理都由系统完成;没有线程库,但是系统提供了调用API函数接口;系统完成线程的上下文切换,系统进行线程调度,并以线程为基本调度单位进行管理。
优点:对于多处理器,核心可以同时调度同一进程的不同线程在不同CPU中运行。线程的阻塞不会影响其他线程的运行。核心例程是多线程的。
缺点:在同一进程中调用系统内核,会降低进程运行效率。
当然也有混合上述两种模型的系统solaris,其中线程的创建在用户级别,线程调度在系统级别。