繁体   English   中英

无法写入2个进程的管道IPC

[英]Unable to write into pipe IPC for 2 processes

我有2个进程('ls'进程和'grep')。 我正在使用管道在两者之间进行通信。 但是grep进程无法从管道中读取。 你能帮我搞清楚为什么会这样吗?

这是我的代码

#include <stdio.h>
#include <stdlib.h>
#include <unistd.h>
#include <errno.h>
int pipe_fd[2];

int main()
{
    pid_t p1,p2;
    char *prog1_argv[4];
    char *prog2_argv[2];
    /* Build argument list */
    prog1_argv[0] = "ls";
    prog1_argv[1] = "-l";
    prog1_argv[2] = "/";
    prog1_argv[3] = NULL;
    prog2_argv[0] = "grep";
    prog2_argv[1] = "s";
    prog2_argv[1] = NULL;
    if (pipe(pipe_fd) < 0)
    {
        printf ("pipe failed");
    }
    p1 = fork();
    if(p1 == 0)
    {
        printf("in child\n");
        close(pipe_fd[0]);
        if(dup2(pipe_fd[1],1)<0)
        {
            printf("dup failed:%d\n",errno);
        }
        close(pipe_fd[1]);
        if(execvp (prog1_argv[0], prog1_argv)<0)
            printf("exec failed");
    }
    if(p1>0)
    {
        printf("im in parent\n");
        waitpid(p1,NULL,0);
        printf("parent: child exited. Now test the pipe\n");
        close(pipe_fd[1]);
        if(dup2(pipe_fd[0],0)<0)
        {
            printf("dup failed:%d\n",errno);
        }
        close(pipe_fd[0]);

        if(execvp (prog2_argv[0], prog2_argv)<0)
            printf("exec failed");

    }

}

你重写你的grep的参数。 尝试:

int main()
{
  pid_t p1,p2;
  char *prog1_argv[4];
  char *prog2_argv[3];
  /* Build argument list */
  prog1_argv[0] = "ls";
  prog1_argv[1] = "-l";
  prog1_argv[2] = "/";
  prog1_argv[3] = NULL;
  prog2_argv[0] = "grep";
  prog2_argv[1] = "s";
  prog2_argv[2] = NULL;
  // ...

从根本上说,在运行grep之前,你不应该等待ls死掉。

ls命令可能会生成如此多的数据,以至于它不能全部存储在管道中,因此ls命令将阻塞,直到另一个进程从管道读取,但另一个进程在尝试读取之前等待ls完成管道里的任何东西。 这是一个僵局。

此外,通过这样等待,您可以强制执行串行执行,从而避免了多个内核的优势。

你应该做一些小的改进。 报告错误有多种方面。 错误应该在标准错误流( stderr )上报告,而不是在stdout 您还应该确保在至少一些错误之后程序不会继续。

您不必测试任何exec*()系统调用的返回值。 如果函数返回,则失败。 而且,您应该确保在此之后退出流程。 在这个计划中,孩子继续并不重要; 在许多程序中,不退出会导致混乱(例如,两个进程试图同时读取标准输入)。

pipe_fd不需要是全局变量。 请确保您的所有邮件以换行符结尾。 你没有包含<sys/wait.h>所以你没有在waitpid()函数的范围内使用原型 - 这通常是一个坏主意。 您应该将编译器设置为繁琐,因此它要求每个函数在使用或定义之前都在范围内具有原型。 您可以在定义中初始化参数列表:

char *prog1_argv[] = { "ls", "-l", "/", NULL };
char *prog2_argv[] = { "grep", "s", NULL };

这有一个至关重要的有益副作用,即没有使用NULL指针切换prog_argv2[1] (正如Matthias在他的回答中所述 。我也删除了数组的大小;第二个的大小为2,需要为3,但是当你这样初始化时,编译器会进行计数。

你正确做的一件事是正确的做法是确保管道文件描述符全部关闭。

这适合我:

#include <stdio.h>
#include <stdlib.h>
#include <unistd.h>
#include <errno.h>

int main(void)
{
    pid_t p1;
    int pipe_fd[2];
    char *prog1_argv[] = { "ls", "-l", "/", NULL };
    char *prog2_argv[] = { "grep", "s", 0 };
    if (pipe(pipe_fd) < 0)
    {
        fprintf(stderr, "pipe failed:%d\n", errno);
        exit(1);
    }
    p1 = fork();
    if (p1 == 0)
    {
        printf("In child\n");
        close(pipe_fd[0]);
        if (dup2(pipe_fd[1], 1) < 0)
        {
            fprintf(stderr, "dup failed:%d\n", errno);
            exit(1);
        }
        close(pipe_fd[1]);
        execvp(prog1_argv[0], prog1_argv);
        fprintf(stderr, "exec failed:%d\n", errno);
        exit(1);
    }
    if (p1 > 0)
    {
        printf("In parent\n");
        close(pipe_fd[1]);
        if (dup2(pipe_fd[0], 0) < 0)
        {
            fprintf(stderr, "dup failed:%d\n", errno);
            exit(1);
        }
        close(pipe_fd[0]);

        execvp(prog2_argv[0], prog2_argv);
        fprintf(stderr, "exec failed:%d\n", errno);
        exit(1);
    }
    fprintf(stderr, "Fork failed:%d\n", errno);
    return(1);
}

暂无
暂无

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM