操作系统原理---处理机的管理(进程管理)
转载地址:http://www.cnblogs.com/CareySon/archive/2012/05/04/ProcessAndThread.html
本博客一部分转载大牛的大作,一部分是鄙人所学札记……
进程的概念:可并发执行的程序,在一个data集合上的运行过程。
引入进程的原因: 多道程序在执行时,需要共享系统资源,从而导致各程序在执行过程中出现相互制约的关系,程序的执行表现出间断性、非封闭性、不可再现性等特征。传统的程序本身是一组指令的集合,是一个静态的概念,无法描述程序在内存中的执行情况,故引入进程的概念。多道程序并发执行,提高系统吞吐量和系统资源利用率。
进程引入带来的问题:为进程建立数据结构产生的空间开销;进程的管理和协调、跟踪、填写和更新数据结构、切换进程、现场保护等产生的时间开销;控制多进程对临界资源的共享和竞争带来的问题等
进程的结构:程序、数据、PCB(进程控制块);进程状态:新建、就绪、执行、阻塞、挂起、阻塞+挂起、就绪+挂起、完成。状态转化图如下:
空 到 新状态 新创建的进程首先处于新状态;
新状态 到 就绪状态 当系统允许增加就绪进程时,操作系统接纳新建状态进程,将它变为就绪状态,插入就绪队列中;
就绪状态 到 执行状态 当处理机空闲时,将从就绪队列中选择一个进程执行,该选择过程称为进程调度,或将处理机分派给一个进程,该进程状态从就绪转变为执行。
执行状态 终止状态执行状态的进程执行完毕,或出现诸如访问地址越界、非法指令等错误,而被异常结束,则进程从执行状态转换为终止状态
对换技术:将内存中暂时不用的进程的程序或数据,换出到外存,以腾出足够的内存空间,把已具备运行条件的进程,或要运行的进程的数据和程序转入的内存。 因为有对换技术,所以才有挂起一说。
进程调度概念:在一个队列中,按照某种方法(算法),选择一个合适的个体的过程
调度目标:1>公平性:防止进程长期不能得到调度而处于饥饿;2>处理机利用效率:尽量提高处理机利用率;3>提高系统吞吐量;4>尽量减少进程响应时间。
进程调度原则:面向用户:响应时间(分时系统),周转时间(批处理系统),截止时间(实习系统)
满足系统的需求:系统吞吐量、处理机利用率、各类资源的平衡使用、公平性及优先级。
调度类型:长程调度(作业外存到内存)、中程调度(挂起程序,从外存到内存亦或内存到外存)、短程调度(进程内内存 到内存)。
进程调度算法:FCFS(First come First Serve)、短进程优先、时间片轮转、基于线程优先级(静态优先级、动态优先级)、剩余时间最短者优先、响应比高者优先的算法。
线程的概念:轻量级进程,程序执行流的最小单元。被系统独立调度和分派的基本单位。
为什么还需要引入线程呢?这是为了减少程序并发执行时系统所付出的额外开销,使操作系 并发执行时系统所付出的额外开销,使操作系统具有更好的并发性
简介
在传统的操作系统中,进程拥有独立的内存地址空间和一个用于控制的线程。但是,现在的情况更多的情况下要求在同一地址空间下拥有多个线程并发执行。因此线程被引入操作系统。
为什么需要线程?
如果非要说是为什么需要线程,还不如说为什么需要进程中还有其它进程。这些进程中包含的其它迷你进程就是线程。
线程之所以说是迷你进程,是因为线程和进程有很多相似之处,比如线程和进程的状态都有运行,就绪,阻塞状态。这几种状态理解起来非常简单,当进程所需的资源没有到位时会是阻塞状态,当进程所需的资源到位时但CPU没有到位时是就绪状态,当进程既有所需的资源,又有CPU时,就为运行状态。
下面我们来看一个具体的例子:
就拿我写博客的LiveWriter来说,LiveWriter需要监听我打字输入的状态,还需要每隔5分钟对草稿进行自动保存。假设如果这个进程只有一个线程的话,那么当对草稿进行保存时,因为此时需要访问硬盘,而访问硬盘的时间线程是阻塞状态的,这时我的任何输入都会没有响应,这种用户体验是无法接受的,或许我们可以通过键盘或者鼠标的输入去中断保存草稿的过程,但这种方案也并不讨好。而使用多线程,每个线程仅仅需要处理自己那一部分应该完成的任务,而不用去关心和其它线程的冲突。因此简化了编程模型。如图1所示。
图1.两条线程满足各自的功能 用户级线程
更具体的说,线程的好处如下:
1.在很多程序中,需要多个线程互相同步或互斥的并行完成工作,而将这些工作分解到不同的线程中去无疑简化了编程模型。
2.因为线程相比进程来说,更加的轻量,所以线程的创建和销毁的代价变得更小。
3.线程提高了性能,虽然线程宏观上是并行的,但微观上却是串行。从CPU角度线程并无法提升性能,但如果某些线程涉及到等待资源(比如IO,等待输入)时,多线程允许进程中的其它线程继续执行而不是整个进程被阻塞,因此提高了CPU的利用率,从这个角度会提升性能。
4.在多CPU或多核的情况下,使用线程不仅仅在宏观上并行,在微观上也是并行的。
这里值得注意的是,上面的两个线程如果改成两个进程,那么达不到所要的效果,因为进程有自己独立的内存地址空间,而线程共享进程的内存地址空间。
经典线程模型
另一个看进程和线程的角度是进程模型基于两类不同的概念:资源的组织和执行。在过去没有线程的操作系统中,资源的组织和执行都是由进程完成的。但区分这两者很多时候需要加以区分,这也是为什么需要引入线程。
进程是用于组织资源的单位,进程将相关的资源组织在一起,这些资源包括:内存地址空间,程序,数据等,将这些以进程的形式组织起来可以使得操作系统管理这些资源更为容易。
而线程,是每一个进程中执行的一个条线。线程虽然共享进程中的大多数资源,但线程也需要自己的一些资源,比如:用于标识下一条执行指令的程序计数器,一些容纳局部变量的寄存器,以及用于表示执行的历史的栈。
总而言之:进程是组织资源的最小单位,而线程是安排CPU执行的最小单位。
其实在一个进程中多个线程并行和在操作系统中多个进程并行非常类似,只是线程共享的是地址空间,而进程共享的是物理内存,打印机,键盘等资源……
每一个进程和线程所独自占有的资源如表1所示。
进程占有的资源 | 线程占有的资源 |
地址空间 全局变量 打开的文件 子进程 信号量 账户信息 |
栈 寄存器 状态 程序计数器 |
表1.进程和线程所独占的资源
其中,线程可以共享进程独占的资源。
我们常用的术语“多线程”一般指的是在同一个进程中多个线程的并发执行。如图2所示。
图2.没有多线程的系统一个进程只能由一个线程 后者是系统级线程
在多线程的进程中,每个线程轮流使用CPU,因此实际上线程并不是并行的,但从宏观上看,是并行的。
在多线程模型中,每一个进程初始创建时只有一个线程。这个线程可以通过调用系统的库函数去创建其它线程。线程创建的线程并必须要为其指定地址,因为新的线程自动在创建它的地址空间内工作。虽然一个线程可以创建另一个线程,但通常来讲,线程之间是并列的,并不存在层级关系。
当一个进程完成其工作后,可以通过调用系统库函数进行销毁。
操作系统实现线程的几种模式
在操作系统中,线程可以实现在用户模式下,也可以实现在内核模式下,也可以两者结合实现。
线程实现在用户空间下
当线程在用户空间下实现时,操作系统对线程的存在一无所知,操作系统只能看到进程,而不能看到线程。所有的线程都是在用户空间实现。在操作系统看来,每一个进程只有一个线程。过去的操作系统大部分是这种实现方式,这种方式的好处之一就是即使操作系统不支持线程,也可以通过库函数来支持线程。
在这种模式下,每一个进程中都维护着一个线程表来追踪本进程中的线程,这个表中包含表1中每个线程独占的资源,比如栈,寄存器,状态等,如图3所示。
图3.在用户空间中实现线程
这种模式当一个线程完成了其工作或等待需要被阻塞时,其调用系统过程阻塞自身,然后将CPU交由其它线程。
这种的模式的好处,首先,是在用户空间下进行进程切换的速度要远快于在操作系统内核中实现。其次,在用户空间下实现线程使得程序员可以实现自己的线程调度算法。比如进程可以实现垃圾回收器来回收线程。还有,当线程数量过多时,由于在用户空间维护线程表,不会占用大量的操作系统空间。
有好处就有坏处,这种模式最致命的缺点也是由于操作系统不知道线程的存在,因此当一个进程中的某一个线程进行系统调用时,比如缺页中断而导致线程阻塞,此时操作系统会阻塞整个进程,即使这个进程中其它线程还在工作。还有一个问题是假如进程中一个线程长时间不释放CPU,因为用户空间并没有时钟中断机制,会导致此进程中的其它线程得不到CPU而持续等待。
线程实现在操作系统内核中
在这种模式下,操作系统知道线程的存在。此时线程表存在操作系统内核中,如图4所示。
图4.线程在操作系统内核中实现
在这种模式下,所有可能阻塞线程的调用都以系统调用(System Call)的方式实现,相比在用户空间下实现线程造成阻塞的运行时调用(System runtime call)成本会高出很多。当一个线程阻塞时,操作系统可以选择将CPU交给同一进程中的其它线程,或是其它进程中的线程,而在用户空间下实现线程时,调度只能在本进程中执行,直到操作系统剥夺了当前进程的CPU。
因为在内核模式下实现进程的成本更高,一个比较好的做法是另线程回收利用,当一个线程需要被销毁时,仅仅是修改标记位,而不是直接销毁其内容,当一个新的线程需要被创建时,也同样修改被“销毁”的线程其标记位即可。
这种模式下同样还是有一些弊端,比如接收系统信号的单位是进程,而不是线程,那么由进程中的哪一个线程接收系统信号呢?如果使用了表来记录,那么多个线程注册则通过哪一个线程处理系统信号?
混合模式
还有一种实现方式是将上面两种模式进行混合,用户空间中进程管理自己的线程,操作系统内核中有一部分内核级别的线程,如图5所示。
图5.混合模式
在这种模式下,操作系统只能看到内核线程。用户空间线程基于操作系统线程运行。因此,程序员可以决定使用多少用户空间线程以及操作系统线程,这无疑具有更大的灵活性。而用户空间线程的调度和前面所说的在用户空间下执行实现线程是一样的,同样可以自定义实现。