【发布时间】:2012-10-26 12:59:54
【问题描述】:
我对 pthread_cond_wait 和 pthread_cond_signal 函数有疑问。在阅读手册页后我也无法理解。
请考虑以下代码。
void* thread_handler(){
... // counts till COUNT_LIMIT is reached
if (count == COUNT_LIMIT) {
pthread_cond_signal(&count_threshold_cv);
printf("inc_count(): thread %ld, count = %d Threshold reached.\n",
my_id, count);
}
printf("inc_count(): thread %ld, count = %d, unlocking mutex\n",
my_id, count);
...
}
void* thread_handler1(){
... // waits till the previous thread has finished counting
pthread_mutex_lock(&count_mutex);
while (count<COUNT_LIMIT) {
pthread_cond_wait(&count_threshold_cv, &count_mutex);
printf("watch_count(): thread %ld Condition signal received.\n", my_id);
}
pthread_mutex_unlock(&count_mutex);
pthread_exit(NULL);
}
代码按预期运行。我正在尝试理解代码。这是程序的工作原理
输入 thread_handler1 并执行 cond_wait。从手册页我了解到 cond_wait 将立即以原子方式释放锁。 那么为什么他们在thread_handler1下面又释放了锁
在第一个线程满足条件并达到条件信号后我希望阻塞的线程执行其步骤。相反,我在执行 cond_signal 的线程下面得到了 printfs。为什么会发生这种情况
总的来说,为什么我们需要在等待和发出信号之前获取锁。没有锁就不能这样做。
有关该程序的简要介绍,请在此处查看Complete program。您可以在“使用条件变量”部分找到它
提前致谢
奇丹巴拉姆
【问题讨论】:
-
请注意,每当您修改
count时,都应锁定互斥锁,并且通常应保持直到调用pthread_cond_signal。 IE。顺序是:锁定、修改、信号(如果“准备好”)、解锁。 -
@WilliamMorris:如果您不需要在发出信号之前阻止新的服务员到达,您将通过在调用
pthread_cond_signal之前解锁互斥锁来获得更好的性能(更少的上下文切换和/或更少往返内核空间)。 -
@R..:无论其他线程上的活动性质如何,保持互斥锁始终处于锁定状态。仅当这些信号事件非常频繁地发生时,性能才是一个问题。您提出的性能问题是否与实现尝试唤醒服务员的确切时间有关?如果它试图在信号传递后立即唤醒,那么显然它不能(因为信号器仍然有互斥锁) - 这可能会对性能产生轻微影响。但是如果实现等到互斥锁被释放,那么性能有什么区别吗?
-
在 Linux 上,互斥锁锁定时发出信号不会唤醒服务员,而是使用特殊的 futex 命令将服务员重新排入互斥锁而不是条件变量。但是,当您随后解锁互斥锁以唤醒服务员时,这需要第二次系统调用,即到内核空间的额外往返。如果互斥体已经解锁,那么信号可以直接唤醒等待者,只需要往返内核空间一次。
-
在没有像 Linux 这样的“requeue”命令的实现上,差异应该更加严重:服务员实际上会被唤醒,然后立即再次阻塞互斥体。我没有测量任何一种实现类型的性能差异,但假设(这通常是正确的)花费的时间主要由系统调用支配,只使用一个系统调用而不是两个应该是可衡量的性能提升。
标签: c linux multithreading pthreads