三个相关进程之间进程间通信的同步

Synchronization of inter process communication between three relative processes

我最近研究了信号主题以及如何使用它们来帮助同步进程。我正在尝试写一些像 Ping-Pong 一样工作的东西。当有 2 个进程(父进程和子进程)时,我可以设法做到这一点并且我的代码工作得很好但是当有 3 个进程(父进程、子进程和孙进程)时,它就不起作用而且我无法弄清楚我做错了什么,请检查我的代码并帮助我。如果输入为 10,则输出应如下所示,程序在输入 10 时正常工作,但如果输入为 3、4、5、7、8、9 等,则它不起作用

孙子 0
儿子 1
父亲 2
儿子 3
孙子 4
儿子 5
父亲 6
儿子 7
孙子 8
儿子 9
父亲 10

编辑:
程序应该做什么:程序中应该有created parent/child 和grandchild 进程。这 3 个进程应该只使用一个管道相互通信。程序等待用户输入正整数。根据这个输入,这3个进程一个一个打印出一个从0开始的数字。比如输入10,进程应该从0打印到1,每个进程只打印一个数字,然后加1。孙子打印出第一个数字。他首先打印 0 并使用管道通道将下一个数字发送给进程子进程。进程子进程打印,将数字加一并发送给父进程。父进程打印该数字,将其加一并将其发送给子进程。如此直到其中一个达到用户输入的数字。

对于输入 1、3、5、7、9,我的程序打印到 2、4、6、8、10,包括这些数字,这是不正确的。 对于输入 4,8,我的程序打印到数字 4 和 8,但一直在等待并且没有 return 任何东西。

#include <stdio.h>
#include <unistd.h>
#include <signal.h>
#include <sys/types.h>
#include <sys/wait.h>

volatile int flag = 0;

void SigHandler(int s)
{
    signal(SIGUSR1, SigHandler);
    flag = 1;
}

int main()
{
    pid_t pid;
    int fd[2];
    int count=0, countMax, queue=0;
    scanf("%d",&countMax);

    signal(SIGUSR1, SigHandler);

    if(pipe(fd) < 0)
    {
        perror("pipe\n");
        return 1;
    }

    if((pid=fork()) < 0)
    {
        perror("fork\n");
        return 2;
    }
    else if(pid == 0)
    {
        //SON
        pid = fork();
        if(pid<0)
        {
            perror("fork\n");
            return 3;
        }
        else if(pid == 0)
        {
            //GRANDSON
            while(count < countMax)
            {
                if(!flag)
                    pause();
                flag = 0;
                read(fd[0], &count, sizeof(int));
                printf("grandson %d\n", count++);
                fflush(stdout);
                write(fd[1], &count, sizeof(int));
                kill(getppid(), SIGUSR1);
            }
            close(fd[0]);
            close(fd[1]);
            return 0;
        }
        else
        {
        //SON
            flag = 0;
            kill(pid, SIGUSR1);
            while(count < countMax)
            {
                if(!flag)
                    pause();
                flag = 0;
                read(fd[0], &count, sizeof(int));
                printf("son %d\n", count++);
                fflush(stdout);
                write(fd[1], &count, sizeof(int));
                if(queue == 0)
                {
                    kill(getppid(), SIGUSR1);
                    queue = 1;
                }
                else
                {
                    kill(pid, SIGUSR1);
                    queue = 0;
                }
            }
            close(fd[0]);
            close(fd[1]);
            return 0;
        
        }
    }
    else
    {
    //FATHER
        write(fd[1], &count, sizeof(int));
        kill(pid,SIGUSR1);
        fflush(stdout);
            while(count < countMax)
            {
                if(count>=countMax)
                    raise(SIGINT);
                if(!flag)
                    pause();
                flag = 0;
                read(fd[0], &count, sizeof(int));
                printf("father %d\n", count++);
                fflush(stdout);
                write(fd[1], &count, sizeof(int));
                kill(pid, SIGUSR1);
            }
        close(fd[0]);
        close(fd[1]);
        return 0;
    }
}

我向程序添加了一些调试输出

#include <stdio.h>
#include <unistd.h>
#include <signal.h>
#include <sys/types.h>
#include <sys/wait.h>

volatile int flag = 0;

void SigHandler(int s)
{
    signal(SIGUSR1, SigHandler);
    flag = 1;
}

int main()
{
    pid_t pid;
    int fd[2];
    int count=0, countMax, queue=0;
    setvbuf(stderr, NULL, _IONBF, 0);
    printf("enter maximum count: ");
    scanf("%d",&countMax);

    signal(SIGUSR1, SigHandler);

    if(pipe(fd) < 0)
    {
        perror("pipe\n");
        return 1;
    }

    if((pid=fork()) < 0)
    {
        perror("fork\n");
        return 2;
    }
    else if(pid == 0)
    {
        //SON
        pid = fork();
        if(pid<0)
        {
            perror("fork\n");
            return 3;
        }
        else if(pid == 0)
        {
            //GRANDSON
            while(count < countMax)
            {
                if(!flag)
                {
                    fprintf(stderr, "@ grandchild pause\n");
                    pause();
                }
                flag = 0;
                fprintf(stderr, "@ grandchild read (after pause)\n");
                read(fd[0], &count, sizeof(int));
                printf("grandson %d\n", count++);
                fflush(stdout);
                write(fd[1], &count, sizeof(int));
                fprintf(stderr, "@ grandchild signal child\n");
                kill(getppid(), SIGUSR1);
            }
            fprintf(stderr, "@ grandchild done\n");
            close(fd[0]);
            close(fd[1]);
            return 0;
        }
        else
        {
        //SON
            flag = 0;
            kill(pid, SIGUSR1);
            while(count < countMax)
            {
                if(!flag)
                {
                    fprintf(stderr, "- child pause\n");
                    pause();
                }
                flag = 0;
                fprintf(stderr, "- child read (after pause)\n");
                read(fd[0], &count, sizeof(int));
                printf("son %d\n", count++);
                fflush(stdout);
                write(fd[1], &count, sizeof(int));
                if(queue == 0)
                {
                    fprintf(stderr, "- child signal parent\n");
                    kill(getppid(), SIGUSR1);
                    queue = 1;
                }
                else
                {
                    fprintf(stderr, "- child signal grandchild\n");
                    kill(pid, SIGUSR1);
                    queue = 0;
                }
            }
            fprintf(stderr, "- child done\n");
            close(fd[0]);
            close(fd[1]);
            return 0;
        
        }
    }
    else
    {
    //FATHER
        write(fd[1], &count, sizeof(int));
        kill(pid,SIGUSR1);
        fflush(stdout);
            while(count < countMax)
            {
                if(count>=countMax)
                {
                    fprintf(stderr, "# parent raise SIGINT\n");
                    raise(SIGINT);
                }
                if(!flag)
                {
                    fprintf(stderr, "# parent pause\n");
                    pause();
                }
                flag = 0;
                fprintf(stderr, "# parent read (after pause)\n");
                read(fd[0], &count, sizeof(int));
                printf("father %d\n", count++);
                fflush(stdout);
                write(fd[1], &count, sizeof(int));
                fprintf(stderr, "# parent signal child\n");
                kill(pid, SIGUSR1);
            }
        fprintf(stderr, "# parent done\n");
        close(fd[0]);
        close(fd[1]);
        return 0;
    }
}

输入 4 我得到这个输出:

enter maximum count: 4                                                                                                                           
# parent pause                                                                                                                                   
- child pause                                                                                                                                    
@ grandchild read (after pause)                                                                                                                  
grandson 0                                                                                                                                       
@ grandchild signal child                                                                                                                        
@ grandchild pause                                                                                                                               
- child read (after pause)                                                                                                                       
son 1                                                                                                                                            
- child signal parent                                                                                                                            
- child pause                                                                                                                                    
# parent read (after pause)                                                                                                                      
father 2                                                                                                                                         
# parent signal child                                                                                                                            
# parent pause                                                                                                                                   
- child read (after pause)                                                                                                                       
son 3                                                                                                                                            
- child signal grandchild                                                                                                                        
- child done                                                                                                                                     
@ grandchild read (after pause)                                                                                                                  
grandson 4                                                                                                                                       
@ grandchild signal child                                                                                                                        
@ grandchild done                                                                                                                                

如您所见,最后 child 已经离开了循环。 grandchild 尝试向 child 发送信号,后者将不再反应,而 parent 正在等待 pause 中的信号,但没有进程会发送信号向 parent.

发送信号

此行为取决于输入值。

编辑

可在 Tevfik Oğuzhan AKSOY 的 .

中找到解决此处所示问题的原始程序的修改版本
#include <stdio.h>
#include <unistd.h>
#include <signal.h>
#include <sys/types.h>
#include <sys/wait.h>

volatile int flag = 0;

void SigHandler(int s)
{
    signal(SIGUSR1, SigHandler);
    flag = 1;
}

int main()
{
    pid_t pid;
    pid_t pidFather = getpid();
    int fd[2];
    int count=0, countMax, queue=0;
   
    scanf("%d",&countMax);

    signal(SIGUSR1, SigHandler);

    if(pipe(fd) < 0)
    {
        perror("pipe\n");
        return 1;
    }

    if((pid=fork()) < 0)
    {
        perror("fork\n");
        return 2;
    }
    else if(pid == 0)
    {
        //SON
        pid = fork();
        if(pid<0)
        {
            perror("fork\n");
            return 3;
        }
        else if(pid == 0)
        {
            //GRANDSON
            while(count < countMax)
            {
                if(!flag)
                {
                    pause();
                }
                flag = 0;
                read(fd[0], &count, sizeof(int));
        if(count<=countMax)
        {
                    printf("grandson %d\n", count++);
                    fflush(stdout);
                    write(fd[1], &count, sizeof(int));
            kill(getppid(), SIGUSR1);
        }
            }
            close(fd[0]);
            close(fd[1]);
            return 0;
        }
        else
        {
            //SON
            flag = 0;
            kill(pid, SIGUSR1);
            while(count < countMax)
            {
                if(!flag)
                {
                    pause();
                }
                flag = 0;
                read(fd[0], &count, sizeof(int));
        if(count<=countMax)
        {
                    printf("son %d\n", count++);
                    fflush(stdout);
                    write(fd[1], &count, sizeof(int));
                    if(queue == 0)
                    {
                                kill(getppid(), SIGUSR1);
                            queue = 1;
                    }
                    else if(queue != 0)
                {
                        kill(pid, SIGUSR1);
                        queue = 0;
                    }
        }
            }
        kill(getppid(), SIGUSR1);
            close(fd[0]);
            close(fd[1]);
            return 0;
        }
    }
    else
    {
        //FATHER
    write(fd[1], &count, sizeof(int));
        kill(pid,SIGUSR1);
        fflush(stdout);
        while(count < countMax)
        {
            if(!flag)
            {
                pause();
            }
            flag = 0;
            read(fd[0], &count, sizeof(int));
        if(count<=countMax)
        {
            printf("father %d\n", count++);
            fflush(stdout);
                write(fd[1], &count, sizeof(int));
                kill(pid, SIGUSR1);
        }
        }
        close(fd[0]);
    close(fd[1]);
        return 0;
    }
}