目录
最短剩余时间优先(Shortest Remaining Time Next)
进程和线程
进程
一个进程是某种类型的一个活动,它有程序,输入,输出以及状态。单个处理器可以被若干进程共享,它使用某种调度算法决定何时停止一个进程的工作,并转而为另一个进程提供服务。
在任何多到程序设计系统中,CPU由一个进程快速切换至另一个进程,使得每个进程各运行几十或几百毫秒。由于CPU在各个进程之间的快速切换,因此每个进程的执行速度是不确定的,进程的执行顺序也是不确定的。对于单处理器系统,由于在一个CPU上的快速切换,因此每个瞬时,只有一个进程在运行,这种情况就是所说的伪并行。
进程状态
* 运行态,即该时刻进程实际在占用cpu
* 就绪态,可运行,但因为其他进程正在运行而暂时终止
* 阻塞态,除非某种外部事件发生,否则进程不能运行
* 终止态,进程停止运行(可能完成,也可能因错误被动结束),移除调度
进程实现
操作系统为了执行进程间的切换,维护一张表格,这张表就是 进程表(也被称为进程控制块)。每个进程占用一个进程表项。该表项包含了进程状态的重要信息,包括程序计数器,堆栈指针,内存分配状况,所打开文件的状态,账号和调度信息,以及其他在进程由运行态转换到就绪态或阻塞态时所必须保存的信息,从而保证该进程随后能再次启动,就像从未被中断过一样。
线程
-
拥有共享同一个地址空间和所有可用数据的能力
-
线程比进程更轻量级,容易创建,容易撤销
-
性能方面的原因。如果多个线程都是cpu密集型的,那么并不能获得性能上的增强,但是如果存在大量的计算和大量的I/O处理,拥有多个线程能在这些活动中彼此重叠进行,从而加快程序的执行速度。
进程模型基于两种独立的概念,资源分组处理与执行。引入线程使得我们将资源和处理执行分开。即进程用于把资源集中到一起,而线程则是在CPU上被调度执行的实体。也就是说进程负责准备运行所需的虚拟环境,线程负责完成任务。
线程实现
同一个进程中的所有线程共享进程提供的虚拟环境内容,每个线程内部又会存在各自独立的堆栈空间,程序计数器等,这些独立的数据保证了线程的正确切换,也就是说这些独立内容就是线程切换时需要保存的内容。
线程状态
和进程一样,线程也存在以下状态:运行,阻塞,就绪或终止。正在运行的线程拥有cpu并且是活跃的。被阻塞的线程正在等待某个释放它的事件。线程之间状态的切换和进程之间的状态切换是一样的。
用户空间实现线程
把整个线程包放在用户空间中实现,内核对线程一无所知,它并不知道线程的存在。内核按照进程调度,进程内部通过运行时系统可以按照自己的意愿对进程内的线程进行切换调度。
这样实现的好处:
-
线程的切换在用户空间完成,不需要陷入内核,也就不需要进行上下文切换(这里不需要上下文切换是指,我们只需要对线程的必要的切换信息进行保存,而不像内核切换进程一样,进行地址空间等各种更耗时的行为,另外就是不需要陷入内核,也就意味着我们减少了两次的上下文切换,即用户-内核,内核-用户,这些都使得线程高效)CPU上下文切换
-
因为是在用户空间实现,所以每个进程都可以自己决定线程的调度算法。
劣势:
-
当发生诸如阻塞事件时,这将使得整个进程内所有的线程都停止运行,即使时间片没有用完。因为内核并不知道线程的存在,当发生阻塞事件时,就按照进程来完成相应的调度行为。阻塞事件比如系统调用,缺页中断。
-
对于一个进程的cpu时间片,如果当前进程内正在运行的线程不主动放弃cpu(比如完成任务),那么它会占用整个时间片。因为是在用户空间实现,所有我们没有时钟中断从而在用户空间完成轮询调度。
内核空间实现线程
内核空间完成线程的实现,那么内核调度的本质就是调度线程。因此每次线程的切换都会是一个很大的开销相比于用户空间的实现。
任何对线程的操作,都会陷入内核。比如创建,终止这些都会在内核中完成。因此线程的创建和销毁都开销比较大。
进程通信
竞态条件
当两个或多个进程读写某些共享数据,而最后的结果却取决与进程运行的精确时序,则称为竞争条件。
临界区
我们把对内存进行访问的程序片段称作临界区域或临界区。一个好的保证使用共享数据的并发进程能够正确和高效的进行协作的解决方案要满足以下4个条件:
-
任何两个进程不能同时处于临界区
-
不应对cpu的速度和数量做任何假设
-
位于临界区外的进程不得阻塞其他进程
-
不能使任何进程无限等待进程临界区
调度算法
批处理系统
先来先服务
先来先服务(first com, first serverd)算法,按照请求顺序为调度进程,为进程分配CPU。整个进程集合按照queue这样的数据结构整理起来,front进程分配cpu开始运行,运行时间不限,不会被中断因运行时间过长。当其阻塞时,队列中的下一个进程开始运行。当阻塞的进程变为就绪态时,重新加入队列尾部排队。
最短作业优先(Shortest Job First)
对现有的进程任务,按照其要完成运行所需的时间降序排序。
最短剩余时间优先(Shortest Remaining Time Next)
调度程序总是选择剩余运行时间最短的那个进程运行。当一个新作业到达时,其整个时间同当前进程的剩余时间作比较。如果 新的进程比当前运行进程所需要更少的时间,当前进程被挂起,而运行新的进程。这种方式能够使短期作业获得良好的服务。
交互式系统
轮询调度 (round-robin)
每个进程都会被分配一个时间段,称为时间片。在这个时间片内运行进程运行。如果时间片结束进程还在运行的话,则抢占其CPU分配给另一个进程。如果进程在时间片结束前阻塞或结束,则CPU立即切换。
将时间轮询调度上下文切换时间设置得太短会导致过多的进程切换从而降低CPU效率,但设置时间太长会导致一个短请求很长时间得不到响应。最好的切换时间在20~50毫秒。
优先级调度
基本思想:每个进程被赋予一个优先级,优先级高的进程优先运行
但是这不意味着高优先级的进程能够永远一直运行下去,调度程序会在每个时钟中断期间降低当前运行进程的优先级。如果此操作导致其优先级降低到下一个最高进程的优先级以下,则会发生进程切换。或者,可以为每个进程分配时间片。当时间片使用完后,下一个高优先级的进程会得到运行的机会。
最短进程优先
批处理系统中的最短作业优先常常伴随最短响应时间,所以也能够用于交互式系统。
保证调度
这种调度算法对用户做出明确的性能保证。若用户工作时有n个用户登陆,则每个用户获得CPU处理能力的1/n。类似地,在一个有n个进程运行的单用户系统中,若所有的进程等价,则每个进程将获得1/n的CPU时间。
彩票调度
其基本思想是为进程提供各种系统资源的彩票。当做出一个调度决策的时候,就随机抽出一张彩票,拥有彩票的进程将获得该资源。
公平分享调度
以上讨论的算法都是按照进程分配,而不考虑进程的拥有者是谁。因此,这样可能会导致用户资源分配不平衡。因此,这里的算法是按照用户进行分配资源,CPU时间。