实验三 进程通信---信号机制
实验名称:?实验三? 进程通信---信号机制
实验目的:?
1. 熟悉?LINUX?支持的信号量机制、管道机制
2. 熟悉?LINUX?系统软中断通信的基本原理?
3.?掌握UNIX/LINUX的管道通信方式
实验内容:
1. 编写程序:用?fork(?)创建两个子进程,再用系统调用?signal(?)让父进程捕捉键盘上来的中断信号(即按^c?键);捕捉到中断信号后,父进程用系统调用?kill(?)向两个子进程发出信号,子进程捕捉到信号后分别输出下列信息后终止:
Child?process1?is?killed?by?parent!
Child?process2?is?killed?by?parent!
父进程等待两个子进程终止后,输出如下的信息后终止:
Parent?process?is?killed!
2. 分析利用软中断通信实现进程同步的机理。
软中断通信是一种通过软件实现的进程间通信方式。它的基本机理是利用操作系统提供的软中断机制,通过向指定的软中断号发送软中断信号来实现进程间的通信。
在Linux中,可以使用系统调用?int?0x80?触发一个软中断。通过在寄存器中设置不同的参数,可以实现各种系统调用,包括进程间通信。
3.?编写程序实现进程的管道通信。用系统调用?pipe(?)建立一管道,二个子进程?P1?和?P2?分别向管道各写一句话:
Child?1?is?sending?a?message!
Child?2?is?sending?a?message!
父进程从管道中读出二个来自子进程的信息并显示(要求先接收?P1,后?P2)。
算法设计与实现(附流程图和源代码):
1.
#include?<stdio.h>
#include?<stdlib.h>
#include?<unistd.h>
#include?<signal.h>
#include?<sys/types.h>
#include?<sys/wait.h>
pid_t?pid1,?pid2;?//?声明pid1和pid2变量
void?child_process(int?id)?{
????printf("Child?process%d?is?created!\n",?id);
????while?(1)?{
????????sleep(1);?//?子进程持续运行
????}
}
void?sig_handler(int?signo)?{
????if?(signo?==?SIGINT)?{
????????printf("Parent?process?received?SIGINT!\n");
????????kill(pid1,?SIGUSR1);?//?向子进程1发送SIGUSR1信号
????????kill(pid2,?SIGUSR1);?//?向子进程2发送SIGUSR1信号
????}
}
void?child_sig_handler(int?signo)?{
????if?(signo?==?SIGUSR1)?{
????????printf("Child?process%d?is?killed?by?parent!\n",?getpid()?-?getppid());
????????exit(0);
????}
}
int?main()?{
????signal(SIGINT,?sig_handler);?//?设置父进程的信号处理函数
????pid1?=?fork();
????if?(pid1?==?0)?{
????????signal(SIGUSR1,?child_sig_handler);?//?设置子进程1的信号处理函数
????????child_process(1);
????}
????pid2?=?fork();
????if?(pid2?==?0)?{
????????signal(SIGUSR1,?child_sig_handler);?//?设置子进程2的信号处理函数
????????child_process(2);
????}
????int?status;
????waitpid(pid1,?&status,?0);?//?等待子进程1终止
????waitpid(pid2,?&status,?0);?//?等待子进程2终止
????printf("Parent?process?is?killed!\n");
????return?0;
}
流程图
???+-------------------+
??|???Main?Process????|
??+-------------------+
?????????|
?????????|?Fork()?1
?????????|
??+-------------------+
??|???Child?Process1??|
??+-------------------+
?????????|
?????????|?Fork()?2
?????????|
??+-------------------+
??|???Child?Process2??|
??+-------------------+
?????????|
??+-------------------+
??|???Main?Process????|
??|???SIGINT?Handler??|
??|???SIGALRM?Handler?|
??|???Waiting?????????|
??|???(sleep)?????????|
??+-------------------+
?????????|
??+-------------------+
??|???Child?Process1??|
??|???SIGINT?Handler??|
??|???SIGALRM?Handler?|
??|???Waiting?????????|
??|???(sleep)?????????|
??+-------------------+
?????????|
??+-------------------+
??|???Child?Process2??|
??|???SIGINT?Handler??|
??|???SIGALRM?Handler?|
??|???Waiting?????????|
??|???(sleep)?????????|
??+-------------------+
?????????|
??+-------------------+
??|???Main?Process????|
??|???SIGINT?Handler??|
??|???SIGALRM?Handler?|
??|???Waiting?????????|
??|???(sleep)?????????|
??|???Send?Signals????|
??|???to?Child????????|
??+-------------------+
?????????|
??+-------------------+
??|???Child?Process1??|
??|???SIGINT?Handler??|
??|???SIGALRM?Handler?|
??|???Waiting?????????|
??|???(sleep)?????????|
??|???Kill?Self???????|
??+-------------------+
?????????|
??+-------------------+
??|???Child?Process2??|
??|???SIGINT?Handler??|
??|???SIGALRM?Handler?|
??|???Waiting?????????|
??|???(sleep)?????????|
??|???Kill?Self???????|
??+-------------------+
?????????|
??+-------------------+
??|???Main?Process????|
??|???Wait?for?Child??|
??|???Processes???????|
??|???Exit????????????|
??+-------------------+
3.?
#include?<unistd.h>
#include?<signal.h>
#include?<stdio.h>
#include?<stdlib.h>
#include?<sys/wait.h>
int?pid1,?pid2;
int?main()?{
????int?fd[2];
????char?outpipe[100],?inpipe[100];
????pipe(fd);
????while?((pid1?=?fork())?==?-1);
????if?(pid1?==?0)?{
????????lockf(fd[1],?1,?0);
????????sprintf(outpipe,?"child?1?process?is?sending?message!");
????????write(fd[1],?outpipe,?50);
????????sleep(5);
????????lockf(fd[1],?0,?0);
????????exit(0);
????}?else?{
????????while?((pid2?=?fork())?==?-1);
????????if?(pid2?==?0)?{
????????????lockf(fd[1],?1,?0);
????????????sprintf(outpipe,?"child?2?process?is?sending?message!");
????????????write(fd[1],?outpipe,?50);
????????????sleep(5);
????????????lockf(fd[1],?0,?0);
????????????exit(0);
????????}?else?{
????????????wait(0);
????????????read(fd[0],?inpipe,?50);
????????????printf("%s\n",?inpipe);
????????????wait(0);
????????????read(fd[0],?inpipe,?50);
????????????printf("%s\n",?inpipe);
????????????exit(0);
????????}
????}
}
流程图
??+-------------------+
??|???Main?Process????|
??+-------------------+
?????????|
??+-------------------+
??|???Pipe?Created????|
??|???(fd[0]?and?fd[1])|
??+-------------------+
?????????|
??+-------------------+
??|???fork()?1????????|
??+-------------------+
?????????|
??+-------------------+
??|???Child?Process1??|
??+-------------------+
?????????|
??+-------------------+
??|???lockf(write)?????|
??|???Write?Message???|
??|???sleep(5)????????|
??|???lockf(unlock)???|
??|???Exit????????????|
??+-------------------+
?????????|
??+-------------------+
??|???Parent?Process??|
??|???fork()?2????????|
??+-------------------+
?????????|
??+-------------------+
??|???Child?Process2??|
??+-------------------+
?????????|
??+-------------------+
??|???lockf(write)?????|
??|???Write?Message???|
??|???sleep(5)????????|
??|???lockf(unlock)???|
??|???Exit????????????|
??+-------------------+
?????????|
??+-------------------+
??|???Parent?Process??|
??|???wait(pid1)???????|
??|???Read?Message????|
??|???Print?Message???|
??|???wait(pid2)???????|
??|???Read?Message????|
??|???Print?Message???|
??|???Exit????????????|
??+-------------------+
调试过程及实验结果(附截图):
思考题:
- 实验内容1的程序段前面部分用了两个?wait(0),它们起什么作用?
wait(0)?用于等待子进程的退出,参数为?0?表示等待任何一个子进程退出。 - 实验内容1的程序段中每个进程退出时都用了语句?exit(0),为什么?
exit(0)?用于终止进程的执行,参数?0?表示正常退出。 - 为何预期的结果并未显示出?
如果预期结果未显示出来,可能是由于程序执行时的环境或者其他因素导致的。你可以检查一下程序是否被正确编译和执行。 - 什么是进程同步??wait(?)是如何实现进程同步的?
进程同步是指多个进程之间按照一定的顺序执行,以保证资源的正确访问。wait()?是一个用于实现进程同步的系统调用,它可以让父进程等待子进程的退出,从而保证子进程的执行顺序。 - 实验内容3的程序中的?sleep(5)起什么作用?
sleep(5)?让进程暂停执行,即睡眠5秒钟。在这里,它的作用是在子进程等待一段时间后再发送信号。 - 实验内容3中的子进程?1?和?2?为什么也能对管道进行操作?
子进程1和2能够对管道进行操作是因为它们继承了父进程的文件描述符,包括管道的读端和写端。因此,它们可以使用这些文件描述符来进行读写操作。
实验小结:
实验小结:
在本次实验中,我们学习了以下几个重要的主题:
1.?进程间通信:通过使用管道,我们成功地实现了父进程和两个子进程之间的通信。管道提供了一个在进程间传递数据的简单方式。
2.?多进程编程:通过使用?`fork()`?系统调用,我们创建了多个子进程。这些子进程可以并发执行,各自有自己的独立执行环境。
3.?信号处理:我们在父进程中使用了信号处理函数来捕捉?`SIGINT`?信号(即按下?`Ctrl+C`),并向子进程发送了?`SIGUSR1`?信号。
4.?进程同步:在父进程中,我们使用?`wait()`?系统调用来等待子进程的退出,从而保证了子进程的执行顺序。
5.?文件描述符:通过创建管道,我们学习了如何使用文件描述符来进行读写操作。
6.?实验反思:在调试过程中,我们遇到了一些警告和错误,比如隐式声明?`wait()`?函数和未包含相应的头文件。这些问题在及时解决后,程序才能成功编译和执行。
总的来说,通过这次实验,我们加深了对进程间通信和多进程编程的理解,同时也熟悉了一些系统调用和信号处理的使用。同时,及时的调试和解决问题也是非常重要的一部分。
本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。 如若内容造成侵权/违法违规/事实不符,请联系我的编程经验分享网邮箱:veading@qq.com进行投诉反馈,一经查实,立即删除!