Linux - 从管道读取的孩子接收发送到标准输出的调试消息

Posted

技术标签:

【中文标题】Linux - 从管道读取的孩子接收发送到标准输出的调试消息【英文标题】:Linux - child reading from pipe receives debug messages sent to standard output 【发布时间】:2014-03-09 07:17:35 【问题描述】:

我正在尝试创建将通过管道进行通信的父进程和子进程。 我已经将子进程设置为通过管道监听其父进程,并在 while 循环中运行读取命令。

为了调试我的程序,我将调试消息打印到标准输出(请注意,我的读取命令设置为文件描述符不是 0 或 1 的管道)。 由于某种原因,在我的子进程的读取命令中收到了这些调试消息。我不明白为什么会这样。这可能是什么原因造成的?我有什么优雅的解决方案来解决它(除了写入标准错误而不是输出)?

此代码会导致无限循环,因为 cout 消息会触发另一次读取。为什么?请注意,从父进程接收到 CHILD_EXIT_CODE 信号后,子进程就存在了。

int myPipe[2]
pipe(myPipe);
if(fork() == 0)

    int readPipe = myPipe[0];
    while(true)
    
        size_t nBytes = read(readPipe, readBuffer, sizeof(readBuffer));
        std::cout << readBuffer << "\n";
        int newPosition = atoi(readBuffer);
        if(newPosition == CHILD_EXIT_CODE)
        
              exit(0);
        
    

编辑:创建管道和分叉的代码

【问题讨论】:

您应该将调试消息打印到 C 中的 stderr 或 C++ 中的 std::clog 为什么它从输出中读取? 显示设置管道和分叉的代码 如果您在未显示的某个地方关闭stdout,可能会发生这种情况。否则它是不可重现的 (LIVE DEMO)。请发布一个完整的可编译程序来演示该问题。 你应该只发布简化版本(阅读别人的代码并不有趣,如果你不得不分析很多东西只是为了发现它与问题无关)。如果您的简化版本没有出现问题,那么您的解决方案就成功了一半…… 【参考方案1】:

我不知道您的父进程在做什么(您没有发布您的代码),但由于您的描述,您的父进程和子进程似乎共享相同的标准输出流(子进程继承父进程的副本打开文件描述符;见man fork)

我想,你应该做的是将父进程中的 stdout 和 stderr 流附加到管道的写入端(你需要一个用于 stderr 流的管道)

如果我遇到你的情况,这就是我会尝试的(在我看来你错过了dup2):

pid_t pid;              /*Child or parent PID.*/
int out[2], err[2];     /*Store pipes file descriptors. Write ends attached to the stdout*/
                        /*and stderr streams.*/
// Init value as error.
out[0] = out[1] = err[0] = err[1]  = -1;

/*Creating pipes, they will be attached to the stderr and stdout streams*/  
if (pipe(out) < 0 || pipe(err) < 0) 
    /* Error: you should log it */
    exit (EXIT_FAILURE);


if ((pid=fork()) == -1) 
    /* Error: you should log it */
    exit (EXIT_FAILURE);


if (pid != 0) 
    /*Parent process*/
    /*Attach stderr and stdout streams to your pipes (their write end)*/
    if ((dup2(out[1], 1) < 0) || (dup2(err[1], 2) < 0))    
        /* Error: you should log it */
        /* The child is going to be an orphan process you should kill it before calling exit.*/
        exit (EXIT_FAILURE);
    

    /*WHATEVER YOU DO WITH YOUR PARENT PROCESS*/

    /* The child is going to be an orphan process you should kill it before calling exit.*/
    exit(EXIT_SUCCESS);

else 
    /*Child process*/

你不应该忘记几件事:

    wait or waitpid 在子进程死亡时释放相关内存给子进程。必须从父进程调用 wait 或 waitpid。 如果您使用 wait 或 waitpid,您可能需要在调用 fork 之前考虑阻塞 SIGCHLD,在这种情况下,您应该在 fork 之后立即在子进程代码的开头取消阻塞 SIGCHLD(通过 fork 创建的子进程) (2) 继承其父信号掩码的副本;参见sigprocmask)。 . 很多次都被遗忘了。请注意 EINTR 错误。 dup2、waitpid/wait、read 和许多其他都受此错误影响。 如果您的父进程在您的子进程之前死亡,如果您不希望子进程成为孤儿进程,则应尝试终止该子进程。 看看_exit。也许您应该在子进程中使用它而不是退出。

【讨论】:

以上是关于Linux - 从管道读取的孩子接收发送到标准输出的调试消息的主要内容,如果未能解决你的问题,请参考以下文章

C中的进程间通信

从损坏的管道读取时,管道 Python 脚本占用 100% 的 CPU

通过管道读取和写入数据

Linux-C:从管道读取返回写入它的第一个缓冲区

C中的管道,用于读取标准输入的缓冲区

如何从管道 linux 命令连续将输出发送到文件? [复制]