文章目录
- 前言
- 一、进程的执行过程
- 二、进程的示例
- 2.1 示例1所有进程必须有限或者与时钟相关
- 2.2 示例2多进程共享变量
- 2.3 示例3仿真在0时刻结束
- 2.4 示例4仿真变量保持不变
- 总结
前言
本文主要记录一下进程的执行过程,并通过一些例子,帮助进一步理解这个过程。
一、进程的执行过程
- 任意时刻,只有一个事件被执行,其他的进程会被放入READY和WAIT队列中,其中READY队列存放的是,当前时刻将要被执行的事件,WAIT队列存放的是,直到条件满足的阻塞的事件。
- 当前执行的进程进入等待状态时,会进入WAIT队列,接着执行下一个READY进程。
- 当所有的进程进入等待队列时,执行仿真时间。
二、进程的示例
2.1 示例1所有进程必须有限或者与时钟相关
示例1代码如下所示,问这段代码能否正常工作。
答案是否,原因是在第一个进程中,没有与时间相关的阻塞进程,导致仿真一直卡在0时刻,等待第一个进程中的条件满足。
修改后,能够正确执行的代码如下,在多进程中,所有的进程必须有限或者与时钟相关。
2.2 示例2多进程共享变量
示例2代码所示,两个子进程放入了fork-join中,子进程1中的a计算基于b的值,子进程2中的b计算基于a的值,问a和b的最后结果是多少。
结论是a=4, b=8,原因是fork–join会按顺序将两个begin-end包括的子进程放入READY队列,先执行第一个进程得到a=4,再执行第二个进程得到b=8。
2.3 示例3仿真在0时刻结束
示例3代码如下图所示,task send被fork–join_none包括起来,每次调用都放入后台,不阻塞主进程,而主进程在initial中,通过for循环连续调用16次send,问send能否被执行16次。
答案是否,而且仿真在0时刻就结束了,原因是子进程的任务没有在主进程中被阻塞,主进程initial块在0时刻仿真就结束了。
要想子进程能够执行16次,需要在主进程中做阻塞处理,保证子进程都结束了,仿真才结束,修改方案有两个,其一是利用wait fork,等待所有的子进程都结束后,再结束仿真,其二是设置一个变量,子进程执行完就加1,主进程中等到该变量到16的时候,再结束仿真。
具体代码实现,参考如下:
2.4 示例4仿真变量保持不变
接着示例3中的代码,利用wait fork的解决方案,跑完仿真后会发现,传过去的i值一直是16。
通过展开for循环后,会发现原因是,for循环中发送的16次send使用的是同一个变量i,进程执行的时候,首先会将16个send挨个放入READY队列中,然后再去执行send任务的时间阻塞实体,当执行的时候此时的i是16,这就导致16个send传递的i值都是16,图解如下:
要解决上面的问题,可以采用local变量,在for循环中,嵌入一个本地变量index,将i的值赋给这个index,然后再将index传递发送出去。
使用了本地变量后,展开的for循环如下所示,实现了0到15的send。
总结
本文主要记录一下进程的执行过程,并通过几个示例,进一步加深对进程的理解。