问题 是否保证pthread_cond_signal会唤醒等待的线程?


这是一个普遍的问题。例如,当前有两个子线程已调用 pthread_cond_wait(&cond1,&mutex)他们都在等待。然后,父线程调用

pthread_cond_signal(&cond1);
pthread_cond_signal(&cond1);

接下来,我的问题是,是否可以保证两个等待线程都会被唤醒?(假设第一个线程被唤醒,稍后在执行的某个阶段释放互斥,以便第二个线程可以获取它)。

我之所以提出这个问题是因为,对于Unix系统级信号,信号(比如说 SIGCHLD)如果连续传送,则不会排队相同类型的多个信号。所以我不知道是 pthread_cond_signal 如果调度程序碰巧让父线程连续两次发出信号,它们会以不同的方式实现,以便它们不会丢失?


5780
2018-03-18 20:31


起源



答案:


快速回答:

pthread_cond_signal() 会醒来 最后一个 在条件变量上阻塞的线程 - 但不保证更多(参考,使用 pthread_cond_broadcast() 唤醒所有被阻止的线程)。

这里

pthread_cond_signal()调用取消阻塞至少一个线程   在指定的条件变量cond上被阻塞(如果有的话)   线程在cond上被阻止)。

pthread_cond_broadcast()调用当前解除对所有线程的阻塞   在指定的条件变量cond上被阻塞。

答案越长:

所以,根据规范,我假设unblocking同步发生,也就是说,第一次调用已被解除阻塞的线程 pthread_cond_signal() 第二次打电话会被视为畅通无阻 pthread_cond_signal(),因此其他线程将被唤醒。

但是,我不知道你的具体pthread实现是否属于这种情况(目前glibc网站非常狡猾,因此无法访问代码来查看)。

可能还没有实现,但它在规范中的答案:

应该注意的是,最近的规范略有改进,关于如何 pthread_cond_signal() 和 pthread_cond_broadcast() 确定在给定条件变量上实际阻塞了哪些线程,但我认为并非所有实现都已赶上。

可以找到关于该主题的长时间讨论 这里,新规范是:

pthread_cond_broadcast()和pthread_cond_signal()函数   应自动确定哪些线程(如果有)被阻止   在指定的条件变量cond上。这个决心   应在此期间的未指定时间发生   pthread_cond_broadcast()或pthread_cond_signal()调用。   然后pthread_cond_broadcast()函数将解除所有阻塞   这些线程。 pthread_cond_signal()函数应取消阻塞   这些线程中至少有一个。

所以,结论是: 如果不是规范的专家解释者,我会说新文本支持同步发生这种情况的假设 - 因此连续两次调用 pthread_cond_signal()有两个可用的阻塞线程,将唤醒两个线程。

我对此并不是100%肯定,所以如果有人可以详细说明,请随意这样做。


12
2018-03-18 20:35



即使有一个线程在等待(在OPs情况下为2),如果互斥锁在信号发生时被锁定,那么在它被释放之前没有人会去任何地方。更好的问题是,如果你锁定信号 - 信号 - 解锁,两者都接收信号 然后  当互斥锁最终被解锁并且每个都可以获取它时,释放它,然后允许它 其他 线程相同的自由?我老实说不知道。 - WhozCraig
我想@WhozCraig已经问过我的问题。我想另一种问题是,鉴于我在原帖中所说的,这是否意味着两个线程最终都会被唤醒(如果互斥锁被正确解锁),因为父级已经两次调用了pthread_cond_signal? - protossor
啊是的 - 我猜得有点太快了;)我会更新以上内容...... - sonicwave
谢谢!这真的回答了我的问题。 - protossor
所以,更新了我的答案 - 很高兴有所帮助。 - sonicwave


答案:


快速回答:

pthread_cond_signal() 会醒来 最后一个 在条件变量上阻塞的线程 - 但不保证更多(参考,使用 pthread_cond_broadcast() 唤醒所有被阻止的线程)。

这里

pthread_cond_signal()调用取消阻塞至少一个线程   在指定的条件变量cond上被阻塞(如果有的话)   线程在cond上被阻止)。

pthread_cond_broadcast()调用当前解除对所有线程的阻塞   在指定的条件变量cond上被阻塞。

答案越长:

所以,根据规范,我假设unblocking同步发生,也就是说,第一次调用已被解除阻塞的线程 pthread_cond_signal() 第二次打电话会被视为畅通无阻 pthread_cond_signal(),因此其他线程将被唤醒。

但是,我不知道你的具体pthread实现是否属于这种情况(目前glibc网站非常狡猾,因此无法访问代码来查看)。

可能还没有实现,但它在规范中的答案:

应该注意的是,最近的规范略有改进,关于如何 pthread_cond_signal() 和 pthread_cond_broadcast() 确定在给定条件变量上实际阻塞了哪些线程,但我认为并非所有实现都已赶上。

可以找到关于该主题的长时间讨论 这里,新规范是:

pthread_cond_broadcast()和pthread_cond_signal()函数   应自动确定哪些线程(如果有)被阻止   在指定的条件变量cond上。这个决心   应在此期间的未指定时间发生   pthread_cond_broadcast()或pthread_cond_signal()调用。   然后pthread_cond_broadcast()函数将解除所有阻塞   这些线程。 pthread_cond_signal()函数应取消阻塞   这些线程中至少有一个。

所以,结论是: 如果不是规范的专家解释者,我会说新文本支持同步发生这种情况的假设 - 因此连续两次调用 pthread_cond_signal()有两个可用的阻塞线程,将唤醒两个线程。

我对此并不是100%肯定,所以如果有人可以详细说明,请随意这样做。


12
2018-03-18 20:35



即使有一个线程在等待(在OPs情况下为2),如果互斥锁在信号发生时被锁定,那么在它被释放之前没有人会去任何地方。更好的问题是,如果你锁定信号 - 信号 - 解锁,两者都接收信号 然后  当互斥锁最终被解锁并且每个都可以获取它时,释放它,然后允许它 其他 线程相同的自由?我老实说不知道。 - WhozCraig
我想@WhozCraig已经问过我的问题。我想另一种问题是,鉴于我在原帖中所说的,这是否意味着两个线程最终都会被唤醒(如果互斥锁被正确解锁),因为父级已经两次调用了pthread_cond_signal? - protossor
啊是的 - 我猜得有点太快了;)我会更新以上内容...... - sonicwave
谢谢!这真的回答了我的问题。 - protossor
所以,更新了我的答案 - 很高兴有所帮助。 - sonicwave


我知道这是一个旧线程(没有双关语),但典型的实现是这样的:

条件变量将在其中包含当前处于睡眠状态的线程队列,等待它发出信号。

一个锁将有一个已经进入休眠状态的线程队列,因为它们试图获取它但是它被另一个线程持有。

cond_wait将正在运行的线程添加到条件变量的队列中,释放锁定并使其自身进入休眠状态。

cond_signal只是将一个休眠线程从条件变量的队列移动到锁的队列。

当正在运行的线程释放锁时,从锁的队列中移除一个休眠线程,锁的所有权被转移到该休眠线程,并且该休眠线被唤醒。

不要问我为什么规范说cond_signal可能会唤醒多个线程......


0
2018-06-25 23:01