实验名称: 实验三 进程通信---信号机制
实验目的:
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
#include
#include
#include
#include
#include
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
#include
#include
#include
#include
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. 进程间通信:通过使用管道,我们成功地实现了父进程和两个子进程之间的通信。管道提供了一个在进程间传递数据的简单方式。
2. 多进程编程:通过使用 `fork()` 系统调用,我们创建了多个子进程。这些子进程可以并发执行,各自有自己的独立执行环境。
3. 信号处理:我们在父进程中使用了信号处理函数来捕捉 `SIGINT` 信号(即按下 `Ctrl+C`),并向子进程发送了 `SIGUSR1` 信号。
4. 进程同步:在父进程中,我们使用 `wait()` 系统调用来等待子进程的退出,从而保证了子进程的执行顺序。
5. 文件描述符:通过创建管道,我们学习了如何使用文件描述符来进行读写操作。
6. 实验反思:在调试过程中,我们遇到了一些警告和错误,比如隐式声明 `wait()` 函数和未包含相应的头文件。这些问题在及时解决后,程序才能成功编译和执行。
总的来说,通过这次实验,我们加深了对进程间通信和多进程编程的理解,同时也熟悉了一些系统调用和信号处理的使用。同时,及时的调试和解决问题也是非常重要的一部分。