【问题标题】:Problem with C++ pipes when doing a read and write on the same pipe in a process在进程中对同一管道进行读取和写入时出现 C++ 管道问题
【发布时间】:2020-11-04 16:29:01
【问题描述】:

我正在学习管道和叉子。我试图通过使用管道和叉子来表示 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

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

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

【问题讨论】:

  • 我想知道当一个进程从它输出到的同一管道输入时会发生什么?
  • 您的pipefd 对在所有三个进程之间共享。在等效的 shell 命令中,每个管道应该有一对。
  • @Botje 非常感谢您指出这一点。这是一个愚蠢的错误。
  • @user253751 感谢您指出这一点。现在想起来真是一件愚蠢的事情。
  • 我的工作解决方案是这样的:pipe1 为 ps -A 写入,pipe1 为 grep kworker 读取,pipe2 为 grep kworker 写入,pipe2 为 wc -l 读取

标签: c++ linux operating-system pipe fork


【解决方案1】:

看:

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

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

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


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

【讨论】:

  • 感谢您的回答。这并没有解决问题。我只需要添加第二个管道。
  • 这应该可以解决 grep 的输出打印到标准输出的问题。
  • 我们需要关闭写入,以便子进程获得 EOF,如果我们不这样做,我们将继续等待子进程完成。这两个语句之间有一个 wait(0)。
  • @bhristov 使用您的管道布置,grep 正在写入自己的输入,因此它永远不会获得 EOF 是正确的。您的管道布置错误 - 这是“其他问题”。
  • 我假设通过添加第二个管道,管道布置是正确的。如果我错了,请纠正我。因为每两个命令之间会有一个单独的管道,而不是所有 3 个命令之间的一个管道。
猜你喜欢
  • 1970-01-01
  • 2020-08-01
  • 1970-01-01
  • 2019-11-29
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2013-02-17
相关资源
最近更新 更多