多进程的组织、交替、合作

2019-07-01 10:23:24 浏览数 (2)

1.多进程如何组织?

上文中(操作系统之进程管理(1):从CPU如何执行进程说起),我们说过操作系统为每个程序提供了一个叫做PCB(Process Control Block进程控制块)的数据结构。它记录了该程序执行到什么位置,执行过的值的状态、相关寄存器的状态等信息,供CPU再次返回时恢复现场使用。简单来说,PCB就是操作系统为系统进程提供的一种记录进程信息的数据结构

首先,进程有五种状态,PCB记录了进程处于何种状态。

运行态:该进程正在执行。

(运行态--->阻塞态):

遇到IO操作指令时,执行IO指令(如读写磁盘操作),此时进程进入阻塞态。 

(运行态--->就绪态):

因为CPU是按照时间片在各进程间来回切换使进程共同推进的,因此当前进程CPU在其上的时间片过了之后,当前进程重新进入就绪态,等待下一次CPU的时间片来临。

就绪态:进程已经做好了准备,有机会得到CPU的资源,然后就开始执行变为运行态。(就绪态--->运行态)

阻塞态:进程在某些事情发生时不能被CPU调度,必须等待阻塞进程的事件完成,然后进入就绪态,才有机会得到CPU的调度执行变为运行态。如当前进程处于IO操作,此时进程不能被调度,只有IO操作完成之后,变为就绪态,才有机会被调度。(阻塞态--->就绪态)

新建态:刚刚创建的进程,操作系统还没有把它加入到可执行进程组中,通常是(PCB)进程控制块已经创建但是还没有加载到内存中的进程。

终止态:操作系统从可执行进程组中释放出的进程,或由于自身或某种原因停止运行。

多进程的组织方式?

1.有一个进程在执行(运行态)

2.有一些进程在等待被调度执行(就绪态):

3.有一些进程在等待某事件结束(阻塞态)

2.多进程如何交替

pCur为当前执行的进程,执行启动磁盘读写指令后,把该进程PCB放入DiskWaitQueue,即把该进程放入上述的磁盘等待队列,此时pCur当前进程由运行态转化为阻塞态,然后执行schedule()函数,在就绪队列中找到一个处于就绪状态的进程,切换到该就绪进程使其转化为运行态,得到CPU调度执行该进程。

进程交替(schedule()函数)涉及两部分:

1.pNew = getNext(ReadyQueue),从就绪队列中找一个就绪态进程

那么getNext(ReadyQueue)到底以什么策略在就绪队列中寻找一个处于就绪态的进程去执行呢?

这个问题就属于进程调度的范畴了,该问题目前仍然处于一个热点研究之中,下面我列举两种比较常见的进程调度策略。

FIFO(先进先出):即每次选择进程调度的时候就从就绪队列中拿出队首的进程去调度,而刚转化为就绪态的进程就放进队列的尾部。很显然FIFO是公平的策略,先变为就绪态的在队首,后变为就绪态的在其后,先调度先变为就绪态的,后调度后变为就绪态的。但是FIFO没有考虑进程执行的任务区别,有的进程需要紧急执行的,有的进程不需要那么急执行的,显然FIFO策略做不到这一点。

Priority(优先级):每次选择进程调度的时候从队列中选出需要紧急执行的(优先级高)进程,但是这样的策略有可能会使某些进程饥饿,即优先级低的可能永远都得不到被调度的机会,一直在就绪队列中等待。

2.switch_to(pCur, pNew),从当前进程切换到上步中找到的就绪进程调度执行:

切换的过程即为保存pCur当前进程的信息,方便下次调度时恢复现场,然后恢复pNew即将执行的进程的现场,调度pNew进程。此时就完成了两个进程的切换。

值得一提的是:

switch_to(pCur, pNew)函数的代码必须是汇编代码,因为C代码没法精细控制寄存器。

3.多进程如何合作

看以下有关生产者——消费者实例。

定义一个buffer缓冲区,只能装10个元素,定义两个进程,一个叫生产者进程,一个叫消费者进程,定义一个共享数据counter,记录缓冲区的元素个数,当缓冲区不满时,生产者进程不停地往buffer中塞数据,当缓冲区不空时,消费者进程不停地从buffer中取数据出来。

  图1   生产者往缓冲区塞数据 图1 生产者往缓冲区塞数据
 图2  塞进去了 图2 塞进去了
 图3  消费者从缓冲区取数据 图3 消费者从缓冲区取数据

生产者——消费者代码

初始化生产者进程和消费者进程的共享数据

counter:记录缓冲区元素个数。

流程:

生产者进程——塞数据,counter

消费者进程——取数据,counter - -

生产者进程生产者进程
消费者进程消费者进程

因为进程是交替执行的,因此一个可能的执行序列为:

如上图代码,假设当前counter=5,生产者往buffer里塞1个,消费者从buffer取1个,按道理最后counter应该还是等于5,但是按如上图操作序列,最后counter的结果等于4,显然这是不对的。

到底为什么呢?

因为生产者和消费者都对共享变量counter进行了操作!当生产者改变了counter值后,但消费者保存着生产者修改前的值而不是生产者修改后的值,因此造成了共享数据的读写紊乱。

解决该问题的核心在于进程同步(需要合理的进程推进顺序)

当某进程读写共享数据counter时将counter锁住自己用,切断其他进程访问共享数据counter。

还是如上的那个可能的执行序列:

当对共享变量counter进行读写操作的时候,给counter上锁,即生产者访问或者修改counter值时,消费者不得访问或修改counter值,反之,消费者访问或者修改counter值时,生产者不得访问或修改counter值,问题得以解决,这就是进程的同步。

以上就是有关多进程的组织、交替、合作的讲解,各位读者大人若有问题,欢迎后台留言,我将第一时间回复!

欢迎关注我们的微信公众号:IT界的泥石流

0 人点赞