Linux Linux程序练习十六(进程间的通信信号版)

/*
 * 题目:
 * 编写程序,要去实现如下功能:
 父进程创建子进程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>

/*
 * 父进程中,知道所有子进程的pid,所以父进程向子进程1发送带数据的信号,数据是子进程2的pid
 * 子进程1向子进程2发送信号,子进程2向父进程发送信号
 * */

//子进程1信号安装回调函数
void handler1(int sign, siginfo_t * info, void *p)
{
    if (sign == SIGRTMIN)
    {
        printf("子进程1接收到父进程发送的数据:子进程2的pid=%d
", info->si_value.sival_int);
        //向子进程2发送带数据的信号
        union sigval v1;
        v1.sival_int = getpid() * 2;
        if (sigqueue(info->si_value.sival_int, SIGRTMIN,v1) != 0)
        {
            perror("sigqueue() err");
            return;
        }
        //退出子进程1
        printf("子进程1 quit
");
        exit(0);
    }
    printf("子进程1接收到其他信号");
}

//子进程2信号安装回调函数
void handler2(int sign, siginfo_t * info, void *p)
{
    if (sign == SIGRTMIN)
    {
        printf("子进程2接收到数据%d
", info->si_value.sival_int);
        //向父进程发送信号
        if (sigqueue(getppid(), SIGRTMIN, info->si_value) != 0)
        {
            perror("sigqueue() err");
            return;
        }
        //退出子进程2
        printf("子进程2 quit
");
        exit(0);

    }
}

//父进程信号安装回调函数
void handlerf(int sign, siginfo_t * info, void *p)
{
    if (sign == SIGRTMIN)
    {
        //打印信号值
        printf("父进程接收的值是%d
", info->si_value.sival_int);
        printf("game is over!
");
        exit(0);
    }
}

int main(int arg, char *args[])
{
    pid_t pid = 0;
    pid = fork();
    if (pid == -1)
    {
        perror("fork() err");
        return -1;
    }
    if (pid == 0)
    {
        //子进程1
        printf("子进程1的pid=%d
",getpid());
        //安装信号SIGRTMIN,等待父进程发送信号
        struct sigaction act;
        act.sa_sigaction = handler1;
        sigemptyset(&act.sa_mask);
        act.sa_flags = SA_SIGINFO;
        if (sigaction(SIGRTMIN, &act, NULL) != 0)
        {
            printf("sigaction() failed !
");
            exit(0);
        }
        //等待父进程发送信号
        printf("子进程1等待父进程发送信号
");
        while (1)
        {
            printf("子进程1 sleep
");
            sleep(1);
        }
    }
    if (pid > 0)
    {
        //存储子进程1的pid
        pid_t pid_1 = pid;
        pid = fork();
        if (pid == -1)
        {
            perror("fork() err");
            exit(0);
        }
        if (pid == 0)
        {
            //子进程2
            printf("子进程2的pid=%d
",getpid());
            //安装信号SIGRTMIN,等待子进程1发送信号
            struct sigaction act;
            act.sa_sigaction = handler2;
            sigemptyset(&act.sa_mask);
            act.sa_flags = SA_SIGINFO;
            if (sigaction(SIGRTMIN, &act, NULL) != 0)
            {
                printf("sigaction() failed !
");
                exit(0);
            }
            //等待子进程1发送信号
            printf("子进程2等待子进程1发送信号
");
            while (1)
            {
                printf("子进程2 sleep
");
                sleep(1);
            }
        } else if (pid > 0)
        {
            //父进程
            printf("父进程的pid=%d
",getpid());
            //安装信号SIGRTMIN,等待子进程2发送信号
            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 !
");
                exit(0);
            }
            sleep(5);
            //向子进程1发送信号
            printf("父进程向子进程1发送信号
");
            union sigval v1;
            v1.sival_int = pid;
            if (sigqueue(pid_1, SIGRTMIN, v1) != 0)
            {
                perror("sigqueue() err");
                exit(0);
            }
            int ret = 0;
            //等待子进程退出
            while (1)
            {
                ret = wait(NULL);
                if (ret == -1)
                {
                    if (errno == EINTR)
                    {
                        continue;
                    }
                    break;
                }
            }
            //等待信号到达
            while (1)
            {
                sleep(1);
            }
        }
    }
    return 0;
}

/*
 * 错误总结:执行该程序,发现子进程1老是出不来,开始我以为是fork()失败,经过注释代码调试
 * 发现问题出现在父进程的发送信号这个函数上,原因是父进程发送信号的时候,,子进程1刚被创建,还没有执行安装信号函数
 * 而信号SIGRTMIN的默认行为是终止进程,所以子进程刚被创建好了,就被终止了
 *
 * 实际上还有一种方法,可以在fork()之前安装3个不同的信号,3个进程分别接收不同的信号加以处理
 * */
原文地址:https://www.cnblogs.com/zhanggaofeng/p/6123965.html