/*
* 题目:
* 编写程序,要去实现如下功能:
父进程创建子进程1和子进程2、子进程1向子进程2发送可靠信号,并传送额外数据为子进程1的pid*2;
子进程2接受可靠信号的值,并发送给父进程,父进程把接受的值进行打印。
提示:用sigqueue和sigaction实现
* */
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <unistd.h>
#include <errno.h>
#include <sys/types.h>
#include <sys/wait.h>
#include <signal.h>
#include <sys/shm.h>
/* 分析:
* 子进程2将pid存入共享内存区,子进程1从共享内存区中读取子进程2的pid,向子进程2发送带数据的信号
* */
//子进程2信号安装回调函数
void handler(int sign, siginfo_t * info, void *p)
{
if (sign == SIGRTMIN)
{
printf("子进程2接收到数据%d\n",info->si_value.sival_int);
//向父进程发送信号
if (sigqueue(getppid(), SIGRTMIN, info->si_value) != 0)
{
perror("sigqueue() err");
return;
}
//退出子进程2
printf("子进程2 quit\n");
exit(0);
}
}
//父进程信号安装回调函数
void handlerf(int sign, siginfo_t * info, void *p)
{
if (sign == SIGRTMIN)
{
//打印信号值
printf("父进程接收的值是%d\n", info->si_value.sival_int);
}
}
int main(int arg, char *args[])
{
//创建共享内存区
int shmid = shmget(IPC_PRIVATE, sizeof(int), 0666);
if (shmid == -1)
{
printf("shmget() failed !\n");
return -1;
}
pid_t pid = 0;
pid = fork();
if (pid == -1)
{
perror("fork() err");
return -1;
}
if (pid == 0)
{
//子进程1
printf("子进程1的pid=%d\n", getpid());
int *pid2 = NULL;
//子进程1附加到共享内存区
pid2 = (int *) shmat(shmid, 0, 0);
if ((int) pid2 == -1)
{
perror("shmat() err");
return -1;
}
//等待进程2向共享内存区写入数据
while (*pid2 == 0)
{
//等待共享内存区中有数据
sleep(1);
}
//向进程2发送可靠信号
union sigval v1;
v1.sival_int = getpid() * 2;
if (sigqueue(*pid2, SIGRTMIN, v1) != 0)
{
perror("sigqueue() err");
return -1;
}
//发送完信号后,进程1退出
printf("子进程1 exit\n");
exit(0);
}
pid = fork();
if (pid == -1)
{
perror("fork() err");
return -1;
}
if (pid == 0)
{
//子进程2
printf("子进程2的pid=%d\n", getpid());
//安装信号SIGRTMIN
struct sigaction act;
act.sa_sigaction = handler;
sigemptyset(&act.sa_mask);
act.sa_flags = SA_SIGINFO;
if (sigaction(SIGRTMIN, &act, NULL) != 0)
{
printf("sigaction() failed !\n");
return -1;
}
int *mypid = NULL;
//子进程2附加到共享内存区
mypid = (int *) shmat(shmid, 0, 0);
if ((int) mypid == -1)
{
perror("shmat() err");
return -1;
}
//将子进程2的pid放到共享内存区,操作私有共享内存区,映射到系统共享内存区
*mypid = getpid();
//等待子进程1向自己发送信号
while (1)
{
printf("子进程2 sleep\n");
sleep(1);
}
}
//父进程
//安装信号SIGRTMIN
struct sigaction act;
act.sa_sigaction = handlerf;
sigemptyset(&act.sa_mask);
act.sa_flags = SA_SIGINFO;
if (sigaction(SIGRTMIN, &act, NULL) != 0)
{
printf("sigaction() failed !\n");
return -1;
}
int ret=0;
//等待子进程
while(1)
{
ret=wait(NULL);
printf("子进程pid=%d\n",ret);
if(ret==-1)
{
if(errno==EINTR)
{
continue;
}
break;
}
}
//释放共享内存区
if (shmctl(shmid, IPC_RMID, NULL) != 0)
{
printf("shmctl() failed!\n");
}
printf("game is over !\n");
return 0;
}
/*
* 出错总结:gdb报错:shmat() err: Invalid argument,意思是shmat()参数不正确
* 经过半天分析,发现我在父进程中没有wait子进程,直接调用了shmctl()函数,把共享内存给释放了,所以报错
* */