使用管道进行进程间通信

时间:2014-07-20 20:30:17

标签: c fork pipe deadlock file-descriptor

祖父过程应该经过3到N-1的数字。通过管道(filedes)将每个号码发送给父亲。 父亲应该检查管道的内容并为那里的每个数字计算一些东西。如果结果为正,则创建子项以进一步计算它。孩子们应该将他们的结果写入管道(filedes1)给祖父。祖父应该在与父亲沟通之前检查管道。

简而言之:

Grandfather - sends data to Father
Father sends data to Children
Children send data to Grandfather

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

#define N 20

int pid[N],child_no=0;

int prim(int m)
{
    int i;

    for (i=2; i<=m/2; i++)
        if (m%i==0)
            return 0;

    return 1; //prim
}

int check_multiples(int i, int filedes11);

int main()
{
    int filedes1[2], //grandpa->father
        filedes2[2], //father->child
        filedes3[2]; //child->grandpa
        //pid[N],,i=0

    if (pipe(filedes1)<0)
    {
        perror("pipe1");
        exit(EXIT_FAILURE);
    }
    if (pipe(filedes2)<0)
    {
        perror("pipe2");
        exit(EXIT_FAILURE);
    }
    if (pipe(filedes3)<0)
    {
        perror("pipe3");
        exit(EXIT_FAILURE);
    }

    if ((pid[child_no]=fork())<0)
    {
        perror("fork");
        exit(EXIT_FAILURE);
    }
    else
        if (pid[child_no]==0) //father
        {
            int m,v[N],j=0;

            close(filedes1[1]);

            while (read(filedes1[0],&m,sizeof(m)))
            {
                if (prim(m))
                    v[j]=m;

                child_no++;

                if ((pid[child_no]=fork())<0)
                {
                    perror("fork");
                    exit(EXIT_FAILURE);
                }
                else
                    if (pid[child_no]==0)
                    {
                        int k;

                        close(filedes3[0]);
                        for (k=2; k*m<=N; k++)
                        {
                            write(filedes3[1],&(int){k*m},sizeof(k*m));
                            write(filedes3[1], &(int){0}, sizeof(int));
                            exit(0);
                        }
                    }
            }

            int k;
            printf("Prime numbers between 3 and N-1 are: ");
            for (k=0; k<N; k++)
                printf("%d ",v[k]);
            printf("\n");
        }
        else  //grandfather
        {
            int i,m,check=0;

            close(filedes3[1]);
            close(filedes1[0]);
            for (i=3; i<N; i++)
            {
                printf("Checking %d...\n",i);

                if (i!=3)
                {
                    while (read(filedes3[0],&m,sizeof(m))!=0)
                    {
                        printf("%d\n",&m);
                        if (m==0)
                            break;
                        if (i==m)
                        {
                            check=1;
                            break;
                        }
                    }
                }
                printf("Finished checking %d.\n",i);
                if (check==0)
                    write(filedes1[1],&i,sizeof(i));
            }


        }

    return 0;
}

2 个答案:

答案 0 :(得分:2)

程序停留在

            check=read(filedes1[0],&n,sizeof(n));

因为没有人写信给filedes1[1]。如果您注释掉该行,程序将运行至完成。

P.S。请添加行

#include <unistd.h>
#include <sys/wait.h>

到文件。 unistd.hpipe需要forksys/wait.h需要waitpid

答案 1 :(得分:2)

这里有几个问题,但我认为你的问题是

            while (read(filedes3[0],&m,sizeof(m))!=0)
在文件描述符关闭之前,

read不会返回0。并且它从未关闭(即使孩子退出,它也会在父亲中保持开放)。

您应该做的是添加一个特殊标记,指示列表的结尾并读取,直到您获得该标记。我建议0-1作为标记:

            while (read(filedes3[0],&m,sizeof(m))!=0) {
                if (m == 0)
                    break;

您必须删除i == m内的中断,因为您需要在每次迭代时读取标记。

在Child中循环后添加一个带0的写入。您可能还应该在那里拨打exit

                    ...
                    for (k=2; k*m<=N; k++)
                        write(filedes3[1],&(int){k*m}, sizeof(k*m));
                    write(filedes3[1], &(int){0}, sizeof(int));
                    exit(0);

关于其他一些事情。此代码实际上并未使用filedes2。也许那是因为你剪了一些代码。但是你应该在父亲内部打开管道,而不是在祖父内部,否则祖父会保留那些我认为你没想过的那些fds的副本。

这一行错了:

                        write(filedes3[1],k*m,sizeof(k*m));

写入的第二个参数应该是一个指针,并且你给它一个整数。你的编译器应该警告这个。假设您有一个C99编译器,您可以这样写:

                        write(filedes3[1],&(int){k*m},sizeof(k*m));

它被称为复合文字,在C99中被添加。

此代码在增加N时无法很好地扩展。您应该{Child} wait退出。当你这样做时,没有理由使用一系列的pids。如果想要并行启动多个任务,则阵列大小应该是并行任务的最大数量,而不是总任务的数量。

最后,请不要有一个全球名为i。这会让每个人都在阅读代码时感到困惑,可能包括你自己。