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 - 从管道读取的孩子接收发送到标准输出的调试消息的主要内容,如果未能解决你的问题,请参考以下文章