2.2 进程控制
- 进程控制原语
- 进程的创建
- 进程的阻塞和唤醒
- 进程的撤销
- 进程的挂起和激活
一、 进程控制原语
(1) 进程控制
进程控制就是系统中使用了些特定的程序段来创建、撤销进程以及完成进程在各个状态之间的转换。
目的是为了完成多个进程之间高效率的并发执行、协调和共享资源。
控制的类型: 进程的 创建、 阻塞、 唤醒、 挂起、 激活、 撤销等
(2) 原语
原语是系统中的一种特别的程序段, 其本身就是程序;
进程的控制和管理功能是由原语来实现的。
原语是在管态下执行、完成系统特定功能的程序。
原语要么执行,要么不执行,原语的执行过程不允许被中断。
原语中的原字, 体现出了原子性。
一般使用屏蔽中断的技术来保证原语的原子性。
二、 进程的创建
(1)创建进程的原因
原因有很多, 如:
1. 用户提交作业
2. 用户在终端登录
3. 系统创建服务进程
4. 进程创建子进程
(2)创建过程
- 系统从PCB池中取一个空白PCB
- 为新进程的映像分配地址空间,传递环境变量,构造共享地址空间
- 为新进程分配内存等各种资源
- 查找辅存,找到进程正文段并装到正文区中
- 初始化进程的控制块,分配一个唯一的进程标识符, 初始化PSW
- 将进程加入到就绪队列中, 投入运行
(3)linux中的进程创建:
0进程由系统引导时被创建;
系统初启时,0进程创建1进程;
0进程变为对换进程, 1进程变为始祖进程;
进程利用fork()创建其子进程, 形成一颗进程树;
系统中除0进程外的所有进程都是用fork()创建的;
1 . 函数介绍:
fork()创建一个进程;
定义:int fork()
调用:pid = fork()
fork会返回三种类型的值:
0: 在子进程中, pid变量保存的fork()的返回值是0, 表示当前进程是子进程。
大于0:在父进程中, pid变量保存的fork()返回值为子进程的id值(进程标识符)
-1:表示创建进程失败
如果fork被调用成功,则会向父进程返回进程id, 向子进程返回0,也就是说调用一次fork会返回两个值;
fork创建进程的过程, 是一个子进程复制父进程的过程, 也就是子进程是父进程的一个副本,它继承了父进程的很多特性,如代码、数据等,也就是说子进程和父进程有同样的进程上下文(但是PID会不一样)。
2 . 实例:
用父进程创建两个子进程,每一个进程在屏幕上显示不同的字符串;
父进程显示“parent“
子进程p1显示“daughter”
子进程p2显示“son”
实例代码:
#include <stdio.h>
int main()
{
int p1, p2, i;
while((p1 = fork()) == -1); // 防止进程创建失败
/*
子进程的代码数据和父进程一样;
但是子进程的代码执行入口和父进程不一样;
也就是说子进程不会从头执行代码,而是从fork()的下一行开始执行;
父进程的fork返回值p1是子进程的id(一个非负整数);
子进程的fork返回值p1是0;
*/
if(p1 == 0) printf("daughter\n"); // 由子进程p1打印“daughter”
else
{
/* p2子进程同理 */
while((p2 = fork()) == -1) ;
if(p2 == 0) printf("son\n"); // 由子进程p2打印“son”
else printf("parent\n"); // 由父进程打印“parent”
}
return 0;
}
// 父进程和其创建的子进程并发运行;
// 多次运行发现son和daughter输出的先后顺序不一定,这难道就是操作系统的异步性吗?(猜的)
三、进程的阻塞和唤醒
(1)进程阻塞:
进程阻塞需要调用阻塞原语来实现;
阻塞原语是在进程期待某事件发生,但没有发生时,或者所需资源尚不具备时,被该进程调用来阻塞自己;
因此阻塞常常是自我阻塞的过程,进程因没有运行的资源条件自己阻塞自己;
阻塞的过程如图示:
(2)进程唤醒:
由两种唤醒方式:
1 . 系统唤醒进程:由操作系统来实现统一对进程的唤醒;
2 . 事件发生唤醒进程:当某一时间发生时,由某一进程唤醒另一进程;
进程是不能自己唤醒自己的,一定是由其他进程或系统来唤醒的;
唤醒过程如图示:
四、进程撤销
(1)撤销原因:
进程已经完成所要求的功能而正常终止
由于某种错误导致非正常终止
由某一祖先进程要求撤销某个子孙进程
撤销过程如图示:
五、进程的挂起和激活
挂起的过程:(先改状态, 再移数据)
- 先检查被挂起进程的状态, 如果处于就绪态则修改为挂起就绪态,如果处于阻塞态,则修改为挂起阻塞态。
- 再将被挂起进程的PCB的非常驻部分交换到磁盘对换区;
这样做不但会把内存中的代码和数据从内存移到磁盘上, 还可能会把PCB中的一部分内容也移到磁盘上,这样做可以最大限度的腾出内存空间供使用;
激活的过程:(与挂起过程相逆)
- 将PCB中的非常驻部分调进内存并修改状态,挂起状态修改为非挂起状态。
- 再把磁盘中的代码和数据调入内存中去执行;
挂起原语可以由进程自己或者其他进程调用, 而激活原语只能由系统或者其他进程调用;