进程管理是操作系统重要的内容之一,下面给出进程管理实例实现。
实现内容
(1)进程的创建
编写一段程序,使用系统调用fork() 创建两个子进程。当此程序运行时,在系统中有一个父进程和两个子进程活动。让每一个进程在屏幕上显示一个字符:父进程显示字符“a”,子进程分别显示字符“b”和“c”。试观察记录屏幕上的显示结果,并分析原因。
(2)进程的控制
修改已经编写的程序,将每个进程输出一个字符改为每个进程输出一句话,再观察程序执行时屏幕上出现的现象,并分析原因。
如果在程序中使用系统调用lockf () 来给每一个进程加锁,可以实现进程之间的互斥,观察并分析出现的现象。
(3)①编写一段程序,使其现实进程的软中断通信。
要求:使用系统调用fork()创建两个子进程,再用系统调用signal()让父进程捕捉键盘上来的中断信号(即按DEL键);当捕捉到中断信号后,父进程用系统调用Kill()向两个子进程发出信号,子进程捕捉到信号后分别输出下列信息后终止:
Child Processll is Killed by Parent!
Child Processl2 is Killed by Parent!
父进程等待两个子进程终止后,输出如下的信息后终止
Parent Process is Killed!
②在上面的程序中增加语句signal (SIGNAL, SIG-IGN) 和signal (SIGQUIT, SIG-IGN), 观察执行结果,并分析原因。
实现上述内容,进行算法分析(每一个小括号对应一个实现):
(1)分析:从进程并发执行来看,输出bac ,acb等情况都有可能。原因:fork()创建进程所需的时间要多于输出一个字符的时间,因此在主进程创建进程2的同时,进程1就输出了“b”,而进程2和主程序的输出次序是有随机性的,所以会出现上述结果。
(2)分析:由于函数printf()输出的字符串之间不会被中断.因此,字符串内部的字符顺序输出时不变。但是,由于进程并发执行时的调度顺序和父子进程的抢占处理机问题,输出字符串的顺序和先后随着执行的不同而发生变化。这与打印单字符的结果相同。
(3)上述程序中,实用函数signal()都放在一段程序的前面部位,而不是在其他接收信号处。这是因为signal()的执行只是为进程指定信号量16或17的作用,以及分配相应的与.stop( )过程链接的指针。从而,signal( )函数必须在程序前面部分执行。
(4)由于忽略了中断与退出信号,程序会-直保持阻塞状态而无法退出。分析:从进程并发执行来看,输出bac ,acb等情况都有可能。原因:fork()创建进程所需的时间要多于输出一个字符的时间,因此在主进程创建进程2的同时,进程1就输出了“b”,而进程2和主程序的输出次序是有随机性的,所以会出现上述结果。
给出(2)进程控制的实现结果:
由于函数printf()输出的字符串之间不会被中断,因此,每个字符串内部的字符顺序输出时不变。但是,由于进程并发执行时的调度顺序和父子进程的抢占处理机问题,输出字符串的顺序和先后随着执行的不同而发生变化。这与打印单字符的结果相同。
进程互斥的原因是存在两个或两个以上的进程,不能同时进入同一组共享变量的临界区域,否则可能会发生与时间相关的错误,而lockf()函数是将文件区域用作信号量(监视锁),或控制对锁定进程的访问,试图访问已锁定资源的其他进程将返回错误或者进入休态,直到资源解除锁定为止,但以上三个进程在( lockf(1,1,0)锁定标准输出设备,lockf(1,0,0)解锁标准输出设备)lockf(1,1,0)与lockf(1,0,0)中间的for循环不存在共享变量的临界区域,因此输出和原来是一样的。
给出(3)软中断实现:
软中断一般是指由指令int引起的“伪”中断动作——给CPU制造一个中断的假象。Signal函数的原型为:signal(sig,function),它以软中断信号的序号作为参数调用函数,也就是说,收到软中断信号sig后,调用函数function,当子进程1收到进程中断信号16后,调用stop()解除“waiting”,继续往下执行;当进程1打印完句子后就会退出,对于子进程2来说也是这样的。但是父进程在此阶段一直处于“waiting”状态(执行(wait(0)),直到两个子进程都退出后,父进程才会退出。
由于ctrl+c信号会并发传到每个进程中,进程受到该信号会立刻终止。当子进程收到ctrl+c信号时,就终止了,根本不会等父进程传来的软中断信号,因此也就不会打印出child processl1 is killed和child processl2 is killed.
signal(SIGINT, SIG-IGN)和signal(SIGQUIT, SIG-IGN)的作用是屏蔽从键盘上传来的中断信号,因此子进程可以接收到父进程传来的软中断信号,进而将那两句话打印出来。
最后给出实现源码(博主使用putty完成本次实验,使用gcc等指令)
一、进程管理
#include<unistd.h>
#include<math.h>
#include<stdio.h>
void main(void){
int p1,p2,i;
if((p1=fork())==-1){printf("Fork Error/n");}
else if(p1==0){
printf("b");
}
else{
if((p2=fork())==-1){printf("Fork Error/n");}
else if(p2==0)printf("c");
else{
printf("a");
}
}
}
二、进程控制
程序一:
#include<unistd.h>
#include<math.h>
#include<stdio.h>
void main(void){
int p1,p2,i;
if((p1=fork())==-1){printf("Fork Error/n");}
else if(p1==0){
for(i=0;i<3;i++)
printf("daughter:%d\n",i);
}
else{
if((p2=fork())==-1){printf("Fork Error/n");}
else if(p2==0){
for(i=0;i<3;i++)
printf("son:%d\n",i);
}else{
for(i=0;i<3;i++)
printf("parent:%d\n",i);
}
}
}
程序二:
#include<sys/types.h>
#include<sys/wait.h>
#include<unistd.h>
#include<math.h>
#include<stdio.h>
#include<fcntl.h>
#include<errno.h>
#include<signal.h>
#include<stdlib.h>
void main(void){
pid_t p1,p2;
int i;
p1=fork();
if(p1<0){
printf("Fork Error/n");
exit(-1);
}
else if(p1==0){
lockf(1,1,0);
for(i=0;i<3;i++)
printf("daughter:%d\n",i);
lockf(1,0,0);
exit(0);
}
else{
p2=fork();
if(p2==-1){
printf("Fork Error/n");
exit(-1);
}
else if(p2==0){
lockf(1,1,0); /*加锁*/
for(i=0;i<3;i++)
printf("son:%d\n",i);
lockf(1,0,0); /*解锁*/
exit(0);
}else{
lockf(1,1,0); /*加锁*/
for(i=0;i<3;i++)
printf("parent:%d\n",i);
lockf(1,0,0); /*解锁*/
exit(0);
}
}
}
三、
1、
#include<sys/types.h>
#include<sys/wait.h>
#include<unistd.h>
#include<math.h>
#include<stdio.h>
#include<fcntl.h>
#include<errno.h>
#include<signal.h>
#include<stdlib.h>
int w;
void waiting()
{
while(w!=0);
}
void stop()
{
w=0;
}
void main(void){
pid_t p1,p2;
p1=fork();
if(p1<0){
printf("Fork Error/n");
exit(-1);
}
else if(p1==0){
w=1;
signal(16,stop);
waiting();
lockf(1,1,0);
printf("Child Processl1 is killed by Parent!\n");
lockf(1,0,0);
exit(0);
}
else{
p2=fork();
if(p2==-1){
printf("Fork Error/n");
exit(-1);
}
else if(p2==0){
w=1;
signal(17,stop);
waiting();
lockf(1,1,0); /*加锁*/
printf("Child Processl2 is killed by Parent!\n");
lockf(1,0,0); /*解锁*/
exit(0);
}else{
w=1;
signal(SIGINT,stop);//获取到键盘上传来的信号,执行stop函数
waiting();
kill(p1,16);//向子进程p1发送软中断信号16
kill(p2,17);//向子进程p2发送软中断信号17
wait(0);
wait(0);
printf("Partent Process is killed!\n");
exit(0);
}
}
}}
2、
int w;
void waiting()
{
while(w!=0);
}
void stop()
{
w=0;
}
void main(void){
pid_t p1,p2;
//signal(SIGINT,SIG_IGN);
//signal(SIGQUIT,SIG_IGN);
p1=fork();
if(p1<0){
printf("Fork Error/n");
exit(-1);
}
else if(p1==0){
w=1;
signal(16,stop);
signal(SIGINT,SIG_IGN);
waiting();
lockf(1,1,0);
printf("Child Processl1 is killed by Parent!\n");
lockf(1,0,0);
exit(0);
}
else{
p2=fork();
if(p2==-1){
printf("Fork Error/n");
exit(-1);
}
else if(p2==0){
w=1;
signal(17,stop);
signal(SIGINT,SIG_IGN);
waiting();
lockf(1,1,0); /*加锁*/
printf("Child Processl2 is killed by Parent!\n");
lockf(1,0,0); /*解锁*/
exit(0);
}else{
w=1;
signal(SIGINT,stop);//获取到键盘上传来的信号,执行stop函数
waiting();
kill(p1,16);//向子进程p1发送软中断信号16
kill(p2,17);//向子进程p2发送软中断信号17
wait(0);
wait(0);
printf("Partent Process is killed!\n");
exit(0);
}
}
}