7.3 进程管理之暂停、归档和策略

   在上一部分,我们了解了中断机制(包括硬中断、软中断)是实现多任务的硬件基础。在这一部分,我们不再笼统的提多任务,而是具体到实际,采用进程这个概念,并讨论进程的管理问题。

   在现代操作系统中,都采用进程作为程序运行的载体。我们所说的多任务,更多的就是指多个程序并发运行,也就是多个进程的并发执行。对于非多核心CPU来讲,其自身内部机制是顺序执行的,这在中断一部分已经详细介绍了。自然,其上跑的各种应用在微观上来看,也是顺序执行的。而对于多核心CPU(当前市场主流CPU都已经是多核心架构了),虽然内部多个核心可以真正的同时跑多个进程,但是核心的数量还是远远比不上用户习惯中同时运行的程序数量,所以,也不能做到每个或者大部分程序真正意义上的并发执行。实际中,操作系统除了运行用户的程序外,为了实现逻辑上的独立,自身还有大量的管理进程,这些进程也需要占用CPU,这就进一步增加了系统中要运行的进程数量。现在电脑系统中同时存在上百个进程是很常见的现象。因此,在僧多粥少的情况下,操作系统就需要让CPU分身,在多个任务之间切换,以实现宏观上的并行假象。但是,无论是单核心还是多核心架构,CPU分身的基础都是中断这一点是不变的。

  更进一步,可以并发和实现并发还是不一样的。可以只是说有了机制保证;而真正实现,则需要解决诸多的实际问题和细节。程序的并发执行,虽然使得计算机更加易用,体验更好,但是,这种并发并不是无序的并发,而是需要在有效管理下的合理的并发。CPU的资源十分宝贵,要合理分配,不能一些程序长时间占用CPU不释放,而另一些急需要运行的程序又长时间得不到CPU资源。这就是俗话说的,不能饿的饿死撑得撑死,要雨露均沾。所以我们不仅要实现并发,还要一定程度上有序的并发。要解决这个问题,本质上就需要对并发执行进行管理(操作系统中一般叫做调度)。除了并发问题,多进程架构还会带来资源的竞争问题、进程间的通信问题以及进程的安全问题等。其实这些问题综合起来,就是进程管理要做的事情。

   进程管理是操作系统的一个核心功能。通常我们所说的一个程序,一个软件,很大一部分都是一个进程。当然也可能由多个进程展现。不过这里我们以单个情况来讨论,多个的情况可以类推得出。相比程序,进程是一个动态的概念。程序在磁盘上,是一个文件,而进程则是程序被操作系统加载到内存后所运行的单元。如果更进一步的细分,在现代操作系统中,进程更应该表述为资源的载体。而真正并发运行的,或者说调度的,应该是线程才对。对于非多线程的进程而言,就是主线程。进程在内存中,表达了程序运行时需要的各种资源,当然也包括CPU,不过相对而言,更倾向于内存、文件、设备等这类资源。这块随着讨论的深入,都会详细的介绍,这里不再展开。我们先看一个简单的示意图,有个初步的印象。

   磁盘上的程序是一个文件或者一组文件,从物理层面来看,占用了一个个的磁盘块或者扇区。当操作系统将磁盘上二进制格式的程序文件加载到内存中后(通过双击或者shell命令等方式),程序在内存中就会对应一个进程实例。进程实例所包含的主要内容在上图中展示了出来。当然,还有很多细节,在上图中没有体现。比如在操作系统层面,进程的各种资源管理;在应用层面,各种的管理库、栈等。我们可以让操作系统同时运行多个程序,这样内存中就有许多进程实例在运行,并且各个进程实例在操作系统的眼里,其组成结构差不多,都是上图所示的样子。各个程序在内存中的实例以及调度运行,需要操作系统的进程模块来管理。同时,前面已经讲了,操作系统本身也是一个程序,它又是如何在管理进程的同时管理自己的呢?即从底层逻辑上讲,操作系统应该要做到随时接管CPU,暂停某一进程,同时调度另一进程运行;而且,在必要时,操作系统也要做到暂停自己,让别的进程运行。这样一来,操作系统这个程序就不仅是权力有点大,而且自身也显得有点特殊。实事上,操作系统还真不寻常。

   从根源上看,无论是什么代码,不管来自操作系统还是用户编写,最终总是CPU去执行。也不管是什么代码,操作系统程序也罢,用户程序也罢,该执行还是该暂停,也得CPU说了算,或者说CPU得提供这种能力。这是一条基本原则,也是关键原则。从这个角度来看,操作系统管理进程的特殊能力,很显然,是来自CPU、依靠CPU获得的。首先,CPU有一套中断机制,可以保证程序暂停后还能够恢复。这在之前的中断部分已经详细说明过了。因为操作系统是上电后最先运行的,所以,它可以对CPU的中断进行配置,让中断产生时,执行自己写的中断处理代码。在这个优先占有的中断处理中,它可以执行调度管理,从而决定该调度那个进程来执行。其次,CPU提供了一些特殊的寄存器(比如权限寄存器、当前进程内核栈寄存器、虚拟空间相关的描述符寄存器等。ARMX86都是类似的),可以用来控制任务跳转及特权级别等。因为操作系统是最先运行的程序,所以操作系统就可以优先配置CPU,使自己获得更高的权限,掌握中断处理大权;同时控制进程的跳转,并在跳转后,限制应用的权限,使其只能靠自己(陷入OS)来控制系统资源。结合这两点,操作系统就可以做到进程的管理。

   讨论了这么多,还没有说到要紧的地方,那就是操作系统到底是如何进行进程管理的。到目前为止,我们只是说明了操作系统为什么可以做到进程管理,为何有这一特殊能力。虽然操作系统可用占据先机,跟CPU高度配合,但是要做到进程的无缝切换,还是需要一些技巧的。好了,下面我们就具体来看看操作系统到底是如何进行进程管理的。

   一,为进程建立档案

   前面讲了,进程相对程序而言,是一个动态的概念,它并不是一个文件放在那里,操作系统就可以去修改或者做什么,相反,它是处于运行的状态,随时都可能产生变化,这个变化是自身执行过程中产生的。换个说法,当进程处于运行状态时,其就独占了CPU,也就是说,在这一个时间片的运行中,CPU是不受其他模块或者进程控制的。所以,进程的运行有其独占性。

   既然操作系统不能直接干预到进程的运行,那么它又是如何控制进程运行的呢?答案就是前面提的,操作系统的能力来自于其先于用户程序占有CPU并配置了CPU,利用CPU提供的基础能力,实现有利于自己的控制逻辑。具体到进程管理上,其会配置时钟定时器的中断向量,时钟定时器用于计时,可用于计算每一个进程独享CPU资源的时间片大小。当一个进程消耗完自己的时间片后,在下一次定时器发送中断给CPU时,CPU就会暂停当前进程的执行,而去执行时钟中断处理程序。又因为时钟中断处理程序是操作系统提前设计好的,所以控制权就自然的落到了操作系统手里。操作系统会将其时钟中断处理程序设计为类似这样的逻辑:首先为当前被暂停的进程拍一个照,用于记录当前进程的暂停状态,之后把该进程挂起来,其实就是放到进程队列中,然后接着去检查其他之前已经被暂停的进程,找到符合条件的进程,然后让其执行,来消耗下一个时间片的CPU资源,以此类推,不断循环。通过这一过程,操作系统获得了最基础的进程调度能力。这个过程如下图所示:

   上面这个过程的描述,逻辑上是走得通的,但是,内容上,读者会觉得有点笼统。比如说拍照,怎么个拍照法啊?没有说清楚。怎么挂起来,怎么恢复执行等,都还是大大的问号。下面我们就来解决这个问题。

   首先,说拍照。其实,拍照只是个形象的说词,程序和代码都在内存里,都是01010的二进制,怎么拍照?难不成真给内存拍个照,显然不可能。这里说的拍照,本质上是记下来进程执行到那里了。程序以进程的形式在内存中存放,被CPU读取执行,并修改其在内存中的内容。当发生中断时,操作系统需要记下来当前进程执行到哪里了,以便下一次能够正确的恢复。那么操作系统记什么呢,这就是照片里有什么的问题了。因为没有进程能够修改其他进程的内容,连操作系统自己也不行【虽然可以做,但是实际上不会去这么做,没有任何意义】,所以进程本身的内容不用担心被别的进程修改,那么需要记的就是中断发生时,进程代码执行到那个位置了。我们强调了进程虽是动态的,这种动态主要体现在进程的数据上,因为代码是只读的不变的,是事先定好了的逻辑,也不能动。不过,数据虽然可能变化,但也是自娱自乐,自家事情,别的程序管不了,所以,只要自己不改,是不会被别人修改的,无论是处在全局内存区(进程线性空间)、还是动态分配(进程线性空间的堆区)、还是堆栈(无论是用户栈还是内核栈,都是事先分配好的)。这样一来,我们只需要保存好当前堆栈的位置就可以了。除此以外,还有一些保存在CPU中的状态需要记下。CPU中的状态是必须要记住的,其实就是一些寄存器的内容,它们可能保存了一些中间结果。如果不记住的话,CPU下次执行别的进程,这些寄存器的内容就会被覆盖或者修改,当进程再恢复执行时,这些中间结果就找不到了。因此,总结起来看,就是操作系统需要记住当前暂停执行的进程的寄存器状态、代码位置和堆栈位置。但是,这几个都可以通过寄存器关联找到,所以只需要记录寄存器就可以了。这也是进程切换主要做的工作。更进一步的说,操作系统看到的进程,本质上也就是一组状态,它不需要了解进程的具体功能、具体实现等。因此,拍照并不是拍整个进程,其实是拍的CPU的寄存器,也就是记录寄存器的内容。

   不过,单单拿到照片还不够,进程还有一些外围的状态需要关注。前面讲,没人会修改运行中的进程,但这并不代表进程不需要了解其他程序。操作系统中的许多资源都是共享的,比如文件、网络、共享的内存等。举个例子,如果进程打开了一些文件,那么就需要记住这些文件的信息,一旦文件被别的进程修改了,就需要同步一致,否则,就可能导致出错。所以像这些外围状态,操作系统也需要记住。这些状态相比前面主动记录的状态,有点被动的感觉,或者说是被迫的,不得不做,还包括进程在等待的信号等。因为进程可能不单单是由于时钟中断而挂起,也可能是因为需要使用的资源没有准备好,操作系统为了更好的发挥CPU的作用,避免CPU浪费等待,从而将进程挂起。可能的情况比较多,这里就不一一列举。这样,进一步综合起来,操作系统为了管理进程,更像是为进程建立了一个档案,记录了进程相关的很多信息。在程序实现上,一般会在操作系统中定义一个进程管理结构体,专门用来保存进程信息。为了让读者有更具体更直观的感受,这里我们拿Linux中的进程管理结构来看一下。Linux的一个进程管理结构如下:(Linux中,这个结构叫做task struct,并不是进程struct,也不是线程struct。因为Linux并不区分进程和线程,进程和线程的差别在于线程是否共享进程的内存结构,也就是共享进程的资源,而调度执行,是以线程为基本单位进行的。因为这个结构体包含了太多东西,在Linux中,它是一个巨大的结构体。)图片来自http://t.zoukankan.com/5iedu-p-6353729.html

   这样,第一步的建档就完成了。

   二,归档

   操作系统每加载一个程序,创建一个进程,都需要建立一个进程档案。我们的系统正常运行起来后,系统中存在的进程不止一两个,随随便便可能就有几十个,这些进程的管理结构,也就是档案,就不能随随便便的在内存中存放,最好是有一个集中的地方能够统一管理。这就类似于将档案归档。在程序设计上,一般会使用数组或者链表,将所有进程的管理结构体串联起来,如下图所示。归档以后,操作系统查找起来就方便多了。

   上面只是示例。早期任务结构体放在一个固定的位置,提前分配固定大小的页面。现在,内核的内存管理手段已经发生了翻天覆地的变化,任务结构体开始从slab分配器中获取。另外,所有的任务也不再使用一个链表,而是区分等待和运行,区分每CPU,这些都是为了更好的优化对内存的使用和提升整体性能。

   到目前为止,我们还没有介绍内存管理,没有介绍页表,页目录表等概念,读者可能对操作系统如何找到进程的内存空间感到迷惑。其实,在这一部分的开始,我们提到了几个CPU的扩展寄存器,借助这些寄存器,操作系统会有一套内存管理机制,通过内存管理模块,操作系统可以定位任何一个进程的管理结构,这块在内存管理介绍部分会讨论更多细节,读者在此先有一个概念即可。

   三,策略

   通过进程管理结构,操作系统就间接的可以控制进程的加载执行和暂停了。但是有个问题,就是进程的选择?假如系统有几十个进程存在,当前空余出一个时间片,那么操作系统该如何选择要执行的进程?进程的并发执行,不能是混乱无序的,否则,某些可能急需要得到执行的进程就拿不到时间片,而某些不怎么重要的进程可能在那里空转,白白消耗CPU资源。这就是进程调度的问题。这个问题,与其说是一个策略问题,还不如说是z策问题。操作系统的设计者们考虑了很多种策略,有时间片轮转,有优先级方案,等等。但是,总的原则还是既要保证公平公正,让所有进程都有机会执行到,也要有一些特性考量,应该让重要的进程获得更多的执行时间,让用户操作相关的进程得到尽快执行【通过区分计算型和IO型进程,能提高用户操作流畅度】,从而让CPU资源在得到更大限度的利用基础上,发挥更大的作用。可以感觉到,调度有点类似运筹学的一些概念。

   所以,不管现代各个操作系统具体的策略如何,但是总的原则还是没有改变,只是侧重有一些不一样。这里就不再具体介绍了。

   至此,我们完成了进程管理的讨论。在这部分,我们忽略了很多的细节,读者先建立一个整体的概念,随着后续内容的展开,相关的细节会有进一步的讨论,到时,读者会慢慢感受到整个流程越来越清晰。

   后续可以展开的点:

   【与进程管理相关的一些寄存器,包括虚拟内存相关的】

   【进程的创建】

   【进程的调度】

   【进程的负载管理】

   【进程的切换与堆栈】

   【进程间的竞争、通信的问题】

  

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

龙赤子

你的小小鼓励助我翻山越岭

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值