实验三 进程通信---信号机制

发布时间:2023年12月18日

实验名称:?实验三? 进程通信---信号机制

实验目的:?

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. 实验内容1的程序段前面部分用了两个?wait(0),它们起什么作用?
    wait(0)?用于等待子进程的退出,参数为?0?表示等待任何一个子进程退出。
  2. 实验内容1的程序段中每个进程退出时都用了语句?exit(0),为什么?
    exit(0)?用于终止进程的执行,参数?0?表示正常退出。
  3. 为何预期的结果并未显示出?
    如果预期结果未显示出来,可能是由于程序执行时的环境或者其他因素导致的。你可以检查一下程序是否被正确编译和执行。
  4. 什么是进程同步??wait(?)是如何实现进程同步的?
    进程同步是指多个进程之间按照一定的顺序执行,以保证资源的正确访问。wait()?是一个用于实现进程同步的系统调用,它可以让父进程等待子进程的退出,从而保证子进程的执行顺序。
  5. 实验内容3的程序中的?sleep(5)起什么作用?
    sleep(5)?让进程暂停执行,即睡眠5秒钟。在这里,它的作用是在子进程等待一段时间后再发送信号。
  6. 实验内容3中的子进程?1?和?2?为什么也能对管道进行操作?
    子进程1和2能够对管道进行操作是因为它们继承了父进程的文件描述符,包括管道的读端和写端。因此,它们可以使用这些文件描述符来进行读写操作。

实验小结:

实验小结:

在本次实验中,我们学习了以下几个重要的主题:

1.?进程间通信:通过使用管道,我们成功地实现了父进程和两个子进程之间的通信。管道提供了一个在进程间传递数据的简单方式。

2.?多进程编程:通过使用?`fork()`?系统调用,我们创建了多个子进程。这些子进程可以并发执行,各自有自己的独立执行环境。

3.?信号处理:我们在父进程中使用了信号处理函数来捕捉?`SIGINT`?信号(即按下?`Ctrl+C`),并向子进程发送了?`SIGUSR1`?信号。

4.?进程同步:在父进程中,我们使用?`wait()`?系统调用来等待子进程的退出,从而保证了子进程的执行顺序。

5.?文件描述符:通过创建管道,我们学习了如何使用文件描述符来进行读写操作。

6.?实验反思:在调试过程中,我们遇到了一些警告和错误,比如隐式声明?`wait()`?函数和未包含相应的头文件。这些问题在及时解决后,程序才能成功编译和执行。

总的来说,通过这次实验,我们加深了对进程间通信和多进程编程的理解,同时也熟悉了一些系统调用和信号处理的使用。同时,及时的调试和解决问题也是非常重要的一部分。

文章来源:https://blog.csdn.net/qq_42531954/article/details/135047981
本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。