在进程中的同一管道上进行读写时 C++ 管道出现问题

Problem with C++ pipes when doing a read and write on the same pipe in a process

我正在学习管道和叉子。我试图通过使用管道和叉子来表示 ps -A | grep kworker | wc -l 来获取 kworker 进程的数量。在我为 grep 语句执行管道之前,我的代码一直在正常工作。

我运行我的代码是这样的:./a.out kworker

#include <iostream>
#include <unistd.h> // for fork() 
#include <sys/wait.h> // for wait() 

using std::cout;
using std::endl;

int main(int num = 1, char * args[] = NULL)
{
    int pipefd[2];
    pipe(pipefd);
    char * p[3];

    /*
       wait for grandchild to complete ps - A
       wait for child to complete grep kworker
       execute wc -l
    */

    p[2] = NULL;
    pid_t id1 = fork(); // get child process

    if(id1 == -1) 
    {
        perror("fork");

        close(pipefd[0]);
        close(pipefd[1]);
    }
    else if(id1 == 0) // child process
    {
        pid_t id2 = fork(); // get grandchild process

        if(id2 == 0) // grandchild process
        {
            p[0] = "ps";
            p[1] = "-A";

            dup2(pipefd[1], STDOUT_FILENO);

            close(pipefd[0]); // close read
            close(pipefd[1]); 

            execvp(p[0], p);

            perror("exec");
            exit(1);
        }
        else if(id2 > 0) // child process
        {
            // The problem is in this if-statement

            close(pipefd[1]); 

            wait(0);

            p[0] = "grep";
            p[1] = args[1];

            // I get output from the STDOUT

            dup2(pipefd[0], STDIN_FILENO); // read from pipe
            dup2(pipefd[1], STDOUT_FILENO); // write to pipe

            close(pipefd[1]);

            execvp(p[0], p);
        }
    }
    else if(id1 > 0) // parent process
    {
        // close pipes first
        close(pipefd[1]); // close unused write end

        wait(0);

        p[0] = "wc";
        p[1] = "-l";

        dup2(pipefd[0], STDIN_FILENO); // read from pipe

        close(pipefd[1]);
        close(pipefd[0]);

        if(execvp(p[0], p) == -1)
        {
            perror("exec");
            exit(1);
        }
    }
}

代码给我的输出:

      6 ?        00:00:00 kworker/0:0H-events_highpri
     20 ?        00:00:00 kworker/1:0H-kblockd
     26 ?        00:00:00 kworker/2:0H-kblockd
     32 ?        00:00:00 kworker/3:0H-kblockd
     50 ?        00:00:00 kworker/1:1-events
    172 ?        00:00:00 kworker/u17:0-rb_allocator
    289 ?        00:00:00 kworker/3:1H
    290 ?        00:00:00 kworker/1:1H-events_highpri
    296 ?        00:00:00 kworker/0:1H-kblockd
    360 ?        00:00:00 kworker/2:1H-events_highpri
    550 ?        00:00:00 kworker/u17:1-rb_allocator
   1340 ?        00:00:01 kworker/2:4-events
   1374 ?        00:00:00 kworker/0:0-events
   2751 ?        00:00:00 kworker/3:2-events
   2782 ?        00:00:00 kworker/1:2-mm_percpu_wq
   5389 ?        00:00:00 kworker/0:1-events
   6539 ?        00:00:00 kworker/u16:3-events_unbound
   6599 ?        00:00:00 kworker/3:1
   6618 ?        00:00:00 kworker/2:1-events
   6705 ?        00:00:00 kworker/u16:0-events_unbound
   6815 ?        00:00:00 kworker/u16:1-events_unbound
   7283 ?        00:00:00 kworker/u16:2-events_unbound
   0

我希望输出与以下内容相同:

ps -A | grep kworker | wc -l
21

是什么导致了这个问题?我在这里查看了其他问题,但找不到解决方案。

添加第二个管道解决了问题。我们不能同时读取和写入同一个管道。

看:

close(pipefd[1]); 
dup2(pipefd[1], STDOUT_FILENO);

您关闭其中一个 FD。然后将 dup2 与它一起使用。由于 FD 已关闭,dup2 returns 一个错误代码并且不执行任何操作。所以grep的stdout还是正常的stdout。

您的代码还有其他问题。这就是你问的那个。


关于“其他问题”的详细说明:您的代码尝试使用同一个管道两次。 psgrep 从管道读取,grepwc 从管道读取。这意味着数据可以从 ps 直接转到 wc,或者从 grep 返回到它本身,这不是您想要的。您应该使用两个单独的管道 - 一个将 ps 连接到 grep,一个将 grep 连接到 wc.