waitpid 和 pthread_cond_wait(3)

Posted

技术标签:

【中文标题】waitpid 和 pthread_cond_wait(3)【英文标题】:waitpid and pthread_cond_wait(3) 【发布时间】:2012-09-06 12:11:58 【问题描述】:

我正在开发一个使用生产者和消费者线程的 linux 应用程序。这是一个相当成熟的应用程序,我不想过多地改变架构。

生产者和消费者线程通过等待队列链接。这是一个通过 std::queue 以及条件变量和互斥锁实现的类。

现在我希望消费者线程能够派生/执行子进程,并等待子进程完成或可等待队列非空,以先发生者为准。如果等待队列不为空,则必须终止子进程。 编辑:子进程是无法更改的第三方应用程序。

一种可能性是当子进程终止时在我的条件变量上调用 pthread_cond_signal(),但如何实现呢?我不能使用 SIGCHLD 的处理程序,至少不能直接使用,因为man page 说 pthread_cond_signal() 不能从信号处理程序中使用。

一种可能的方法是产生子进程,然后启动一个线程到阻塞的 waitpid(),最后是 pthread_cond_signal()。不过,这似乎有点笨拙:我真的需要生成一个线程来监视 pid 吗?

对于混合 waitpid 和 select/poll/epoll,有 Self Pipe Trick。混合等待PID和条件变量是否有任何等价物?

注意 1: 在某些实现中,SIGCHLD 会中断条件变量等待函数。这不是可移植的,如果可能的话,我宁愿不依赖这种行为。

注意 2: 由于条件变量封装在可等待队列类中,我需要扩展该类以允许应用程序向互斥体发出信号。这只是一个微不足道的实现细节,我在我的问题中已经掩饰了。

【问题讨论】:

@user1548637:有趣的想法,但我无法更改子应用程序。他们都是第三者。为了清楚起见,我会将其添加到我的问题中。 @user1548637:您对帮助应用程序的建议会很好,因为那时我只需要一个帮助应用程序来处理所有不同的子应用程序。如果可能的话,我仍然想要一个不涉及额外进程或线程开销的解决方案。 因为你不能让你的子进程做任何类型的工作(这对于让它与你交互是必要的),你可能不会有任何其他的解决方案,而不是执行多个锁定功能(在不同的线程中)。虽然我可以想到其他方式,但我不确定您是否可以从信号处理程序内部发出信号。 或者如果你可以使用信号量锁,它也可以代替发出信号(但我认为这是可能的)。你知道吗? @user1548637:信号量的唯一问题是我需要使用仅适用于 CLOCK_REALTIME 的 sem_timedwait()。条件变量通过 pthread_condattr_setclock() 允许 CLOCK_MONOTONIC 作为选项。这对我来说很重要,因为目标平台可能会不时地重新同步其系统时钟。我将研究将 CLOCK_MONOTONIC 与信号量一起使用的方法...... 【参考方案1】:

也许这行得通,但我不确定:

创建一个信号量,该信号量将在您的等待队列中注册,并在等待队列本身要更改其自己的锁以指示状态更改时锁定/更改/解锁。你应该在它持有信号量的同时改变它自己的互斥锁。

SIGCHLD 实现一个信号处理程序,然后在第 3 方应用程序终止时执行信号量锁定/更改/解锁,如果不是这种情况,则不执行任何操作。

在上述情况下,他们将等待 1 并在您的信号量上递增(作为一个信号量操作),当他们想要获取信号量锁时,然后做他们的工作然后更改信号量到 0(减 2)以便为您的等待线程解锁它。这样,您就不会从任何队列/第 3 方应用程序中连续获得两个成功的锁。

在您的实际线程中,应该等待第 3 方应用程序终止或等待队列,您基本上让它在等待 0 时等待同一信号量上的锁定(并减少它,如果有其他服务员为 0)。如果获得了锁,则检查等待队列上的互斥锁是否已释放。如果没有,您知道您的第 3 方应用程序已终止。您执行您的工作,然后通过递增将信号量更改为 1,从而再次为您的队列和第 3 方应用程序解锁信号量。

由于信号处理程序可以中断semop(2)-lock 调用,因此您必须检查EINTR 并循环您的任何锁定尝试。

如果保证信号处理程序将完成它的执行(我认为确实如此),这可能会起作用。

【讨论】:

以上是关于waitpid 和 pthread_cond_wait(3)的主要内容,如果未能解决你的问题,请参考以下文章

waitpid 函数详解

父子信号的waitpid

wait和waitpid详解转

linux wait 和waitpid

函数wait和waitpid

exit,_exit,wait,waitpid