【问题标题】:Pipes and Forks管子和叉子
【发布时间】:2011-05-05 17:13:03
【问题描述】:

该项目的目标是使用管道和分叉来执行已经以多进程方式编写的行计数实用程序(每个参数一个进程)。我目前正在努力让单个进程在扩展以处理多个参数之前工作。

给定两个可执行文件lc1lc2,我希望lc2建立到lc1的stdout文件描述符的管道,这样当execlp("lc1", argv[1], NULL)被调用时,输出将被读入
while ((c= read(pipefd[0], readin, SIZE)) > 0)

根据我的 Unix 书,我应该使用 open、dup2、close 方法将标准输出重定向到标准输入,这是我的代码:

int pid, c, i;
char *readin= (char *)malloc(sizeof(SIZE));

if (pipe(pipefd)== -1)
  perror("Can't open a pipe\n");

for (i=1; i< argc; i++){
if ((pid= fork())==-1)
        perror("Can't fork\n");

  run(argv[i]);

}

//close pipe
close(1);
if (dup2(pipefd[0], 0)==-1)
  perror("Can't redirect stdin");
close(pipefd[1]);

for (i=1; i< argc; i++){
    if ((wait(NULL))== -1)
        perror("Wait error");

    while ((c= read(pipefd[0], readin, SIZE)) > 0){;
        //print buf count
        total += atoi(readin);
    }
}

运行函数是

void run(char *f){
  int fp;
  if ((fp= open(f, O_RDONLY)) == -1)
      perror("Can't open the file");

  close(pipefd[0]);
  dup2(pipefd[1], 1);
  close(pipefd[1]);
  execlp("ls1", f, NULL);
} 

当我尝试执行此代码时,我收到一个 stdin 重定向错误,说明文件描述符错误。为什么会发生这种情况,并希望得到任何修复提示。

【问题讨论】:

  • 你的 malloc 语句是错误的我认为你想要 char *readin= (char *)malloc(SIZE);
  • 永远不要在 C 中转换 malloc() 的返回值。请参阅 stackoverflow.com/questions/953112/…
  • 不是你的直接问题,但你真的是说 malloc(sizeof(SIZE)) 吗?我假设 SIZE 是一个常数,所以你分配了 4 或 8 个字节左右。您可以发布更完整的代码吗?正如发布的那样,这有点难以理解。
  • SIZE其实是一个整数4096,所以我用它来分配4MB内存
  • malloc(sizeof(SIZE)) 将在您的机器上分配整数的大小。 malloc(SIZE) 其中 SIZE 的值为 4096 将分配 4k。

标签: c linux pipe


【解决方案1】:

run(argv[i]) 由父子进程执行,因为没有根据返回的 PID 分配功能,因此一个接一个地关闭可能已经关闭。 看下面的代码,他能用得着吗,我会在这种情况下使用代码示例。 :

int main()
{
    int pipe_fd[2] = {0};
    int pid = -1;
    int status = -1;
    int ret_value = INVALID_CMD;
    int cmd_output_len = -1;
    status = pipe(pipe_fd);
    if(status<0)
    {
        perror("pipe create err");
    }
    else
    {
        pid = fork();
        if(pid<0)
        {
        }
        else if (pid == 0)
        {
            /*Child functionality*/
            child_func(pipe_fd, cmd);
        }
        else
        {
            /*Parent functionality*/
            cmd_output_len = parent_fun(pid, pipe_fd);
        }
    }
    return ret_value;
}

int child_func(int pipe_fd[], const char * cmd)
{
    int status = 5;
    int read_fd = pipe_fd[0];       /*read file descriptor*/
    int write_fd = pipe_fd[1];      /*write file descriptor*/

    int exit_status = 0;

    /*close read fd*/
    close(read_fd);

    /*dup2 stdout to write fd*/
    //status = dup2(1, write_fd);
    status = dup2(write_fd, 1);
    if(status<0)
    {
        exit(-1);
    }
    else
    {
        system(cmd);
        exit(0);
    }
}


int parent_fun(int child_id, int pipe_fd[])
{
    int status = -1;
    int len = 0;
    bool_e break_loop = FALSE;
    int read_fd = pipe_fd[0];       /*read file descriptor*/
    int write_fd = pipe_fd[1];      /*write file descriptor*/

    /*close write fd*/
    close(write_fd);

    while(1)
    {
        sleep(1);
        status = waitpid(child_id, &status, WNOHANG);
        switch(status)
        {
            case 0:
                    /*Child is still active*/
                    printf("No process waiting to exit..\n");
                    len = do_ur_fun(read_fd);
                    write(1, output, len);
                break;
            /*case EINTR:
            case ECHILD:
            case EINVAL:
                    perror("waitpid error");
                    break_loop = TRUE;
                break;*/
            default:
                if(status<0)
                {
                    perror("waitpid error");
                    break_loop = TRUE;
                    len = -1;
                }
                else if(child_id == status)
                {
                    /*Valid staus from child*/
                    len = read_output(read_fd, output);
                    //write(1, output, len);
                    break_loop = TRUE;
                }
                else
                {
                }
                break;
        }
        if(TRUE == break_loop)
        {
            break;
        }
    }
    return len;
}




int do_ur_fun (int read_fd)
{
        /*Do your exec*/
}

【讨论】:

    【解决方案2】:

    MaheshGupta024 在您的代码中发现了一个非常重要的问题;我假设你会解决这个问题。

    其他问题领域之一是:

    close(1);
    if (dup2(pipefd[0], 0)==-1)
        perror("Can't redirect stdin");
    close(pipefd[1]);
    
    for (i=1; i< argc; i++){
        if ((wait(NULL))== -1)
            perror("Wait error");
    
        while ((c= read(pipefd[0], readin, SIZE)) > 0){;
            //print buf count
            total += atoi(readin);
        }
    }
    

    第一次关闭关闭进程的标准输出;这很少是一个好主意。下一行将管道的读取端复制到标准输入 - 这很好。如上面评论中所述,perror() 不会退出。然后关闭管道的写入端 - 这是正确的;但是您应该也应该关闭管道的读取端,因为您已将其设置为来自管道。

    您的循环开始正常; wait() 行中有多余的括号。您从pipefd[0] 读取而不是标准输入 - 所以也许您不想关闭 pipefd[0] 但您也不需要将其复制到标准输入。然后,您有一个嵌套循环,可以在管道上读取更多数据,同时要从子级读取更多数据 - 您绝对不需要带有循环的 wait() 代码,因为内部 while 不会终止,直到所有子级都死了.另一方面,这并没有太大的危害——在第一个孩子死后,您将从所有其他孩子那里读取数据,然后进入外循环并等待其他孩子,内循环立即终止没有数据可供读取。

    所以:

    • 不要关闭标准输出。
    • 不要复制管道读取到标准输入。
    • 决定是否要清理循环 - 它会起作用,但可能会更干净。

    run() 函数是:

    void run(char *f){
      int fp;
      if ((fp= open(f, O_RDONLY)) == -1)
          perror("Can't open the file");
    
      close(pipefd[0]);
      dup2(pipefd[1], 1);
      close(pipefd[1]);
      execlp("ls1", f, NULL);
    }
    

    参数应为const char *f(或使用namefile 而不是f)。我还将pipefd 数组传递给函数,而不是使用全局变量 . 不要调用文件描述符fp;该名称通常表示FILE * 类型的变量,而不是int。 但是,您不需要首先打开文件 - 除非您希望调用程序而不是调用程序来执行错误报告。但是,如果您确实希望调用程序执行错误报告,则应在继续之前关闭文件描述符。 (我已经评论了perror()返回)。

    最好在execlp() 之后打印错误消息;函数返回的唯一时间是它失败的时候,所以不需要测试它的返回值。您可能也想退出 - 而不是在调用 run() 后让失败的函数通过主程序的其余部分。

    优点:您确实关闭了两个管道文件描述符。

    因此:

    void run(const char *file, int *pipefd)
    {
        close(pipefd[0]);
        dup2(pipefd[1], 1);
        close(pipefd[1]);
        execlp("ls1", f, NULL);
        perror("Failed to exec ls1");
        exit(EXIT_FAILURE);
    }
    

    【讨论】:

      猜你喜欢
      • 2018-05-26
      • 1970-01-01
      • 2017-07-07
      • 1970-01-01
      • 2017-04-27
      • 2021-07-26
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      相关资源
      最近更新 更多