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>
#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()函数,把共享内存给释放了,所以报错
 * */

posted on 2016-12-01 22:56  寒魔影  阅读(587)  评论(0编辑  收藏  举报

导航