首页 > 解决方案 > 在进程中对同一管道进行读取和写入时出现 C++ 管道问题

问题描述

我正在学习管道和叉子。我试图通过使用管道和叉子来表示 kworker 进程的计数ps -A | grep kworker | wc -l。我的代码工作正常,直到我为 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

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

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

标签: c++linuxoperating-systempipefork

解决方案


看:

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

您关闭其中一个 FD。然后你使用 dup2 。因为 FD 已关闭,所以 dup2 返回错误代码并且不执行任何操作。所以grep的stdout还是正常的stdout。

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


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


推荐阅读