使用带有标准输入和标准输出重定向的 2 进程管道时如何避免标准输入上的重复输入

Posted

技术标签:

【中文标题】使用带有标准输入和标准输出重定向的 2 进程管道时如何避免标准输入上的重复输入【英文标题】:How to avoid duplicate input on stdin when using 2-process pipeline with stdin and stdout redirect 【发布时间】:2019-11-05 03:05:06 【问题描述】:

我打算在两个进程之间建立管道:父进程和子进程。父进程分叉子进程并使用 execve 将其映像替换为指定进程的映像。

父级通过 std::getline(std::cin, input_line) 从标准输入读取。 孩子通过 std::cout

我希望设置一个管道并将子级的输出重定向到父级的输入。

问题在于父级接收每个输入(其中每个输入是子级在标准输出上输出的数字)两次。我想解决这个问题,但我不明白为什么会这样。

代码使用g++ 7.4.0和C++11标准版编译。

Child 被编译为名为“p1”的二进制文件。

父代码:

#include <sys/types.h>

#include <sys/wait.h>

#include <unistd.h>

#include <iostream>

char *
  const p1argv[] = 
    (char * )
    "./p1",
    nullptr
  ;
char *
  const p1envp[] = 
    (char * ) nullptr
  ;

int main(int argc, char ** argv) 

  pid_t p1id;
  int p1fd[2];

  pipe(p1fd);
  if (p1id = fork() == 0) 

    close(p1fd[0]);
    dup2(p1fd[1], STDOUT_FILENO);

    execve(argv[0], p1argv, p1envp);
    perror("Error: failed to execve ./p1.");

   else 

    dup2(p1fd[0], STDIN_FILENO);
    close(p1fd[1]);

    std::string line;
    while (std::getline(std::cin, line)) 
      std::cout << "d(" << line << ")" << std::endl;
    

    int status;
    waitpid(p1id, & status, 0);

    close(p1fd[0]);
  

子代码:

#include <iostream>
#include <thread>

int main(int argc, char** argv) 
    long it = 0;
    while(true) 
        it += 1;
        std::cout << std::to_string(it) << std::endl; 
        std::this_thread::sleep_for(std::chrono::seconds(2));
    

示例代码的实际输出为:

d(d(1)) d(d(2)) ...

预期的输出是:

d(1) d(2) ...

【问题讨论】:

可能无法解决您的问题,但 p1id = fork() == 0 是可疑的。 p1id 将始终为 0 或 1,因为首先评估 fork() == 0 【参考方案1】:

问题在于这一行:

 execve(argv[0], p1argv, p1envp);

正在重新执行主父程序,因为此时argv[0]的内容就是这样。我想你想找到一些方法来在那里指定"./p1"

【讨论】:

以上是关于使用带有标准输入和标准输出重定向的 2 进程管道时如何避免标准输入上的重复输入的主要内容,如果未能解决你的问题,请参考以下文章

将进程的标准输出重定向到多个管道

Linux shell编程:管道和重定向

linux学习第一周;标准输入输出和错误重定向与管道

标准I/o重定向和管道

重新点亮shell————管道和重定向[二]

Linux学习笔记 第六章标准IO和管道