一、实验内容
设计一个程序,该程序有一个父进程和三个子进程,初始阶段输出如下内容:
Parent-hello-0
Child1-hello-1
Child2-hello-2
Child3-hello-3
Parent-hello-4
依次类推,每条信息间间隔1s。顺序不能乱。
当程序运行一段时间后,按下CTRL+C,此时输出如下内容:
Child3-finished
Child2-finished
Child1-finished
Parent-finished
每条信息间隔1s。顺序不能乱。(提示: 用signal 捕捉信号,kill发送信号)
二、实验代码
#include <signal.h>
#include <unistd.h>
#include <sys/wait.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <sys/ipc.h>
#include <sys/types.h>
#include <sys/msg.h>
int status = -1; //当前运行进程状态
key_t key;
int msgid;
typedef struct{
long type;
int num;
} Msg;
Msg msg, rcv; //消息
void func_kill(int sig)
{
if (status == 0) {
msgrcv(msgid, &rcv, sizeof(rcv) - sizeof(rcv.type), 1, 0);
printf("Parent-hello-%d\n", rcv.num);
} else {
msgrcv(msgid, &rcv, sizeof(rcv) - sizeof(rcv.type), 1, 0);
printf("Child%d-hello-%d\n", status, rcv.num);
}
msg.num = rcv.num + 1; //加1
msg.type = 1;
msgsnd(msgid, &msg, sizeof(msg) - sizeof(msg.type), 0);
}
void func_back(int sig)
{
sleep(4 - status);
if (status == 0) {
printf("Parent-finished!\n");
} else {
printf("Child%d-finished!\n", status);
}
msgctl(msgid, IPC_RMID, NULL); //删除消息队列
signal(SIGINT, SIG_DFL);
exit(0);
}
int main()
{
pid_t pid[4] = {0, 1, 2, 3};
int i;
pid[0] = getpid();
key = ftok("/home/china", '6');
msgid = msgget(key, IPC_CREAT | 0777); //创建消息队列
for (i = 1; i < 4; i++) {
pid[i] = fork(); // 创建子进程
sleep(1);
if (pid[i] < 0) {
printf("The fork is error!\n");
exit(0);
} else if (pid[i] == 0) {
break;
}
}
signal(SIGINT, func_back);
while (1) {
if (pid[1] > 0 && pid[2] > 0 && pid[3] > 0) {
signal(SIGCONT, func_kill); //接受唤醒信号
if (status == -1) {
status = 0;
sleep(2);
printf("Parent-hello-0\n");
msg.type = 1;
msg.num = 1;
msgsnd(msgid, &msg, sizeof(msg) - sizeof(msg.type), 0);
//发送消息
}
sleep(1);
kill(pid[3], SIGCONT); //发送唤醒信号
pause();
} else if (pid[1] > 0 && pid[2] > 0 && pid[3] == 0) {
signal(SIGCONT, func_kill);
if (status == -1) {
status = 1;
pause();
}
sleep(1);
kill(pid[2], SIGCONT);
pause();
} else if (pid[1] > 0 && pid[2] == 0 && pid[3] > 0) {
signal(SIGCONT, func_kill);
if (status == -1) {
status = 2;
pause();
}
sleep(1);
kill(pid[1], SIGCONT);
pause();
} else if (pid[1] == 0 && pid[2] > 0 && pid[3] > 0) {
signal(SIGCONT, func_kill);
if (status == -1) {
status = 3;
pause();
}
sleep(1);
kill(pid[0], SIGCONT);
pause();
}
}
return 0;
}
此代码参考的湘大好心学长的,这里以我有限的能力做下个人的理解
创建三个子进程,创建消息队列,在父进程和三个子进程中无限循环并接收唤醒信号,接收到唤醒信号后立马调用函数将信息加入消息队列,之后再把原始信息加1,同时函数中也打印出实验需求的数据;执行完成后睡眠1秒,然后唤醒下一个进程,当前进程则调用pause()函数停止,等待下一次唤醒;其他进程同上,当监听到ctrl + C时,调用结束函数,四个进程,每个进程睡眠时间为4-(第几个),父进程为第0个。然后删除消息队列。
实验效果图如下