线程和分支:从popen()读取时fgetc()阻塞 - 管道

时间:2016-08-17 13:17:41

标签: c++ linux multithreading

在多线程程序中(在ARM上运行)我有

主线程,其中包括定期检查popen( "pidof -s prog" )是否正在运行其他程序。我使用O_CLOEXEC标志作为文件描述符,并检查fgetc()是否从管道接收任何内容。 设置文件描述符"非阻塞"导致无法阅读并赢得任何帮助。 shell命令中的pidof命令运行正常。

在另一个帖子中,子进程中具有立即fork()的{​​{1}}用于在发生特定事件时启动execl()操作。父级使用信号处理程序来观察子级状态,并可以选择在另一个特定事件中杀死子级。我是否使用rsyncexec()调用rsync并不重要 - 结果是相同的。

问题是主线程中的sleep会阻塞,直到子进程终止。

我会尽早fgetc()尝试解决这个问题(在应用程序是单线程的某个时刻,就像我开始的another post中所假设的那样)。 / em>的

但无论如何:

我想了解在从管道中读取时导致fork()阻止的原因。

到目前为止我尝试过的一些事情:

  • 我尝试使用一个小例子应用程序来重现问题,该应用程序执行我上面描述的并且希望它会显示相同的错误行为,但很遗憾它工作正常,这就是为什么我这里还没有提供任何代码。也许我错过了相关的观点。
  • 通过fgetc()使用相同的rsync调用不会导致任何问题
  • 我查看过system() implementation,可以看到信号在system()之前被操纵:

    • SIGCHLD被阻止
    • 忽略SIGINT和SIGQUIT

    我需要SIGCHLD的信号处理程序,但出于好奇,我试图像上面的代码一样(我用fork()替换sigprocmask()) - 没有任何成功,行为保持不变同样的。

    我无法在我的BSP提供的资源中找到pthread_sigmask()的任何实施。

该程序通过system()打开其他文件 - 没有O_CLOEXEC(将有点cumbersome to change that

1 个答案:

答案 0 :(得分:0)

错误修正和意外行为的解释

确实,我错过了相关的观点。在将示例程序更多地调整到原始代码示例之后,我已经看到信号处理程序(在测试程序中工作)是问题。摘录:

void MyClass::sig_handler(int sig) {
    if( m_pid < 1 ) // not the child we're waiting for
        return;

    pid_t pid;
    int wstatus;

    while ((pid = waitpid( -1, &wstatus, WNOHANG )) != -1 ) {
        // error: this returns 0 as long as any children are alive
        // -> check for "> 0" to ignore active child processes
        if( pid != m_pid )
            return;
        // handle stuff here...
    }
}

我必须更换以下行

while ((pid = waitpid( -1, &wstatus, WNOHANG )) != -1 )

while ((pid = waitpid( -1, &wstatus, WNOHANG )) > 0 )

因为该程序的其他帖子fork()个孩子(例如popen())。如果这些终止,则也会调用信号处理程序(静态类函数)。

据我所知:

在我调用fork()的主题中,我使用具有默认值和重置值m_pid的成员-1。需要来自fork()的pid。如果m_pid为-1,则sig处理程序立即返回。

该程序在popen() fork()处被阻止(可能是fork() s的任何其他呼叫)。因此,popen()返回时输入SIGCHLD的信号处理程序。调用m_pid时会调用m_pid = fork()waitpid()不会返回-1但是popen()子项的pid,然后继续检查返回值= 0,直到所有孩子都终止 - 我等待的那个还活着!只有这样waitpid()才会返回-1,主线程可以继续使用fgetc()进行阅读。

来自waitpid的手册页:

  

如果指定了WNOHANG并且由pid指定了一个或多个子(ren)   存在,但尚未改变状态,则返回0。出错,-1   被退回

因为sig处理程序检查m_pid != -1,所以只有当我在MyClass中使用fork()来设置m_pid时才会出现问题。

这就是为什么使用system()不会导致问题的原因。 m_pid未设置为值!= -1,因此sig处理程序会立即返回,例如一个孩子在主线程中popen()

system()调用的模仿失败,因为我已将m_pid设置为fork(),因此sig处理程序未立即返回。

我想因为sig处理程序是static member function,所以处理程序会阻塞fork()编写子进程的线程。