操作系统课内实验报告
分析如下:1) signal函数
上述程序中,调用函数signal()都放在一段程序的前面部位,而不是在其他接收信号处。这是因为signal()的执行起的作用只是为进程指定信号量16和17,以及分配相应的与stop()过程连接的指针。因而signal()函数必须在程序前面部分执行。
2)wait函数
在父进程中调用第1个wait(0)后,则父进程被阻塞。进入等待第一个子进程运行结束的队列,等待子进程结束。当子进程结束后,会产生一个终止状态字,系统会向父进程发出SIGCHLD信号。当接到信号后,父进程提取子进程的终止状态字,从wait()返回继续执行原程序。同样的方式,父进程继续执行第二个wait(0),并再次阻塞,等待第2个子进程运行结束。当第二个子进程运行结束后父进程继续执行剩余的语句。
3)关于exit函数
函数中每个进程退出时都用了语句exit(0),这是进程的正常终止。在正常终止时,exit()函数返回进程结束状态。进程终止时,则由系统内核产生一个代表异常终止原因的终止状态,该进程的父进程都能用wait()得到其终止状态。在子进程调用exit()后,子进程的结束状态会返回给系统内核,由内核根据状态字生成终止状态,供父进程在wait()中读取数据。若子进程结束后,父进程还没有读取子进程的终止状态,则子进程就变成了“孤儿进程”,系统进程init会自动“收养”该子进程,成为该子进程的父进程,即父进程标识号变成1,当子进程结束时,init会自动调用wait()读取子进程的遗留数据,从而避免在系统中留下大量的垃圾。
4)结果显示
上述结果中“Child process 1 is killed by parent !!”和“Child process 2 is killed by parent !!”相继出现,当运行几次后,谁在前谁在后是随机的。这是因为:从进程调度的角度看,子进程被创建后处于就绪态。此时,父进程和子进程作为两个独立的进程,共享同一个代码段,分别参加调度、执行,直至进程结束。但是谁会先被调度程序选中执行,则与系统的调度策略和系统当前的资源状态有关,是不确定的。因此,谁先从fork()函数中返回继续执行后面的语句也是不确定的。 1. 管道通信
实验结果如下:
29
操作系统课内实验报告
图3.5管道通信结果
多次实验
简要分析如下:
管道,是指用于连接一个读进程和一个写进程,以实现它们之间信息的共享文件又称pipe文件。向管道(共享文件)提供输入的发送进程(即写进程),以字符流形式将
30
操作系统课内实验报告
大量的数据送入管道;而接收管道输送的接收进程(读进程),可以从管道中接收数据。
为了协调双方的通信,管道通信机制必须提供以下3方面的协调能力:
互斥。当一个进程正在对pipe进程读/写操作时,另一进程必须等待,程序中使用lock(fd[1],1,0)函数实现对管道的加锁操作,用lock(fd[1],0,0)解除管道的锁定。
同步。当写进程把一定数量的数据写入pipe后,便去睡眠等待,直到读进程取走数据后,再把它唤醒。当读进程试图从一空管道中读取数据时,也应睡眠等待,直至写进程将数据写入管道后,才将其唤醒。
判断对方是否存在。只有确定写进程和读进程都存在的情况下,才能通过管道进行通信。
二者的先后次序是随机的。
3.6实验总结
3.6.1实验中的问题与解决过程
1.编辑器不太会用,后来在网上找了资料,去图书馆借了书,看了一些,大概明白了一些。
2.程序编写方面,一些错误找了很久,经过不断调试,终于解决了。 3.一些概念不是很清楚,通过阅读相关文献有了一些大致的了解。 3.6.2实验收获
1.学习了Linux下的C语言编程流程; 2.进一步理解了进程同步互斥的概念; 3.对进程通信加深了理解。 3.6.3意见与建议
1.希望能得到更贴切的实验指导;
2.希望能进一步对Linux环境下的编程进行研究; 3.互动再多一些就好了。
3.7附件
1.软终端通信源代码:
#include
#include
31
操作系统课内实验报告
#include
int pid1, pid2; // 定义两个进程号变量 signal(3,stop); // 或者 signal(14,stop); while((pid1 = fork( )) == -1); // 若创建子进程1不成功,则空循环
if(pid1 > 0) { // 子进程创建成功,pid1为进程号 while((pid2 = fork( )) == -1); // 创建子进程2 if(pid2 > 0) { wait_flag = 1;
sleep(5); // 父进程等待5秒 kill(pid1,16); // 杀死进程1 kill(pid2,17); // 杀死进程2 wait(0); // 等待第1个子进程1结束的信号 wait(0); // 等待第2个子进程2结束的信号 printf(\ exit(0); // 父进程结束 } else {
wait_flag = 1;
signal(17,stop); // 等待进程2被杀死的中断号17 printf(\
exit(0); } } else { wait_flag = 1; signal(16,stop); // 等待进程1被杀死的中断号16 printf(\ exit(0);
} }
void stop( ) {
wait_flag = 0; }
2.管道通信源代码:
#include
int pid1,pid2; // 定义两个进程变量 main( ) { intfd[2];
char OutPipe[100],InPipe[100]; // 定义两个字符数组 pipe(fd); // 创建管道
while((pid1 = fork( )) == -1); // 如果进程1创建不成功,则空循环 if(pid1 == 0) { // 如果子进程1创建成功,pid1为进程号 lockf(fd[1],1,0); // 锁定管道
sprintf(OutPipe,\ // 给Outpipe赋值 write(fd[1],OutPipe,50); // 向管道写入数据
sleep(5); // 等待读进程读出数据
32
操作系统课内实验报告
lockf(fd[1],0,0); // 解除管道的锁定 exit(0); // 结束进程1 } else {
while((pid2 = fork()) == -1); // 若进程2创建不成功,则空循环 if(pid2 == 0) { lockf(fd[1],1,0);
sprintf(OutPipe,\ write(fd[1],OutPipe,50); sleep(5);
lockf(fd[1],0,0); exit(0); } else {
wait(0); read(fd[0],InPipe,50); printf(\ wait(0); read(fd[0],InPipe,50); printf(\
exit(0); } } }
// 等待子进程1 结束 // 从管道中读出数据 // 显示读出的数据 // 等待子进程2 结束 // 父进程结束 33