【问题标题】:Questions about Systm calls like fork() and pipe() in C关于 C 中的 fork() 和 pipe() 等 Systm 调用的问题
【发布时间】:2014-03-20 07:45:18
【问题描述】:
   #include<stdio.h>
   #include<stdlib.h>
   #include<unistd.h>
   #include<sys/wait.h>
   #include<errno.h>

   int main(int argc, char **argv){
       int n = atoi(argv[1]);
       int superdaddy = getpid();
       int p[n+1][2];
       int i=0;
       int cpid,output;
       int result = 0;

       if(pipe(p[0])<0){
           perror("1");
           return 1;
       }
       if(pipe(p[n])<0){
           perror("2");
           return 1;
       }
       output = p[0][1];
       if(getpid()==superdaddy){
           if(write(p[0][1],&result,sizeof(result))<0){
               perror("3");
               return 1;
           }
           if(close(p[0][1])<0){
               perror("4");
               return 1;
           }
       }
       while(1){
           if(i==n){
               if(read(p[n-1][0],&result,sizeof(result)<0)){
                   perror("5");
                   return 1;
               }
               result++;
               output = p[n][1];
               if(write(output,&result,sizeof(result))<0){
                   perror("6");
                   return 1;
               }
               if(close(p[n-1][0])<0){
                   perror("7");
                   return 1;
               }
               if(close(p[n][1])<0){
                   perror("8");      
                   return 1;
               }
               break;
           }
           i++;
           cpid = fork();
           if(cpid==0){
               if(i==n)
                   continue;
               if(pipe(p[i])<0){
                   perror("9");
                   return 1;
               }
               if(read(p[i-1][0],&result,sizeof(result))<0){
                   perror("10");
                   return 1;
               }
               result++;
               output = p[i][1];
               if(write(output,&result,sizeof(result))<0){
                   perror("11");
                   return 1;
               }
               if(close(p[i-1][0])<0){
                   perror("12");
                   return 1;
               }

               if(close(p[i][1]<0)){
                   perror("13");
                   return 1;
               }
               continue;
           }
           else if(cpid<0){
               perror("14");
               return 1;
           }
           break;
       }

       if(getpid()==superdaddy){
           wait(NULL);
           if(read(p[n][0],&result,sizeof(result))<0){
               perror("15");
               return 1;
           }
           printf("Result: %d\n",result);
           if(close(p[n][0])<0){
               perror("16");
               return 1;
           }
       }
       return 0;
   }

该程序旨在从命令行读取一个数字 n,然后分叉 n 个子进程并创建 n 个管道。进程p0 将是进程p1 的父进程,p1 将是p2 的父进程,依此类推。一个变量(这里命名为结果)将通过管道传递,每次传递它都会加 1。所以输出也应该是 n。管道Fi 连接PiP(i+1)。附上我的代码。

n=1n=2时,程序可以正确输出,对应的是1和2。但是,当 n=3 时,它在错误 5 处给了我一个错误的文件错误。我已经手动跟踪了整个下午的代码,但不知道它有什么问题。任何人都可以帮忙吗?先欣赏一下!

【问题讨论】:

  • 我已经删除了行号。给您带来的不便,我们深表歉意。

标签: c pipe


【解决方案1】:

当 n=3 时,它在错误 5 处给我一个错误的文件错误。

这可以通过删除代码中的 if(close(p[i][1]&lt;0)){ 来解决,因为您需要在最后一次迭代中读取 p[i][0],即

if (i == n) {
    if(read(p[n-1][0],&result,sizeof(result)<0)){
        ...
    }
}

这是你想法的一个实现,希望对你有帮助:

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

int
main(int argc, char *argv[])
{
    if (argc != 2) {
        fprintf(stderr, "Usage: %s N\n", argv[0]);
        exit(EXIT_FAILURE);
    }

    int n = atoi(argv[1]);
    int pipes[n][2];
    int i, val;
    pid_t pid;

    val = 0;

    for (i = 0; i < n; i++) {
        if (pipe(pipes[i]) < 0) {
            perror("pipe");
            exit(EXIT_FAILURE);
        }
        if ((pid = fork()) < 0) {
            perror("fork");
            exit(EXIT_FAILURE);
        }
        else if (pid == 0) {
            close(pipes[i][1]);
            if (read(pipes[i][0], &val, sizeof(val)) != sizeof(val)) {
                perror("read");
                exit(EXIT_FAILURE);
            }

            printf("C %d read %d\n", getpid(), val);

            val++;
        }
        else {
            close(pipes[i][0]);

            printf("P %d writes %d\n", getpid(), val);

            if (write(pipes[i][1], &val, sizeof(val)) != sizeof(val)) {
                perror("write");
                exit(EXIT_FAILURE);
            }

            if (waitpid(pid, NULL, 0) != pid) {
                perror("waitpid");
                exit(EXIT_FAILURE);
            }
            printf("%d is going to leave.\n", getpid());
            exit(EXIT_SUCCESS);
        }
    }

    printf("%d is going to leave.\n", getpid());
    exit(EXIT_SUCCESS);
}

测试运行:

$ ./a.out 3
P 2005 writes 0
C 2006 read 0
P 2006 writes 1
C 2007 read 1
P 2007 writes 2
C 2008 read 2
2008 is going to leave.
2007 is going to leave.
2006 is going to leave.
2005 is going to leave.

解释:

该代码的框架是for (i = 0; i &lt; n; i++) { pipe(); fork(); },这意味着它将创建n 管道和n 新进程。在每次迭代中,父级将写入pipes[i][1],子级将从pipes[i][0] 读取。最终,它将创建一个由一系列管道连接的进程链,并通过该系列管道将一个值从第一个进程传递到最后一个进程。

【讨论】:

  • 2008怎么可能读2不能写3?我的意思是你的测试数据是否适用于我的代码。
  • 另外,你的实现并不正确,因为如果输入为 3,输出应该为 3,即必须有一个 3 写入 pipe[3] 并且 superdaddy 将从 pipe[3 读取] 然后输出 3 作为答案。
  • @AnbangLi 输出来自我的代码,而不是你的。而且我的代码是对您的想法的重新实现(当然,根据我的理解),而不是您的代码的修复版本。
  • @AnbangLi 我相信我的实现是正确的。因为该代码的框架是for (i = 0; i &lt; n; i++) { pipe(); fork(); },这意味着它将创建n 管道和n 新进程。在每次迭代中,父级将写入pipes[i][1],子级将从pipes[i][0] 读取。最终,它将创建一个由一系列管道连接的进程链,并通过该管道系列将一个值从第一个进程传递到最后一个进程。
  • 好吧,我相信你是对的,但是你知道为什么我的程序在 n=3 时会出现这个错误吗?
猜你喜欢
  • 1970-01-01
  • 2013-05-28
  • 1970-01-01
  • 2021-12-07
  • 2012-09-12
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多