pthread_cond_wait() 同时唤醒两个线程
Posted
技术标签:
【中文标题】pthread_cond_wait() 同时唤醒两个线程【英文标题】:pthread_cond_wait() waking up two threads at the same time 【发布时间】:2015-07-15 21:04:42 【问题描述】:我试图更好地了解如何使用pthread_cond_wait()
以及它是如何工作的。
我只是想对我在这个网站上看到的答案进行一些澄清。
答案是本页最后的回复
understanding of pthread_cond_wait() and pthread_cond_signal()
我想知道使用三个线程会如何。想象一下线程 1 想告诉线程 2 和线程 3 唤醒
例如
pthread_mutex_t mutex;
pthread_cond_t condition;
线程 1:
pthread_mutex_lock(&mutex);
/*Initialize things*/
pthread_mutex_unlock(&mutex);
pthread_cond_signal(&condition); //wake up thread 2 & 3
/*Do other things*/
线程 2:
pthread_mutex_lock(&mutex); //mutex lock
while(!condition)
pthread_cond_wait(&condition, &mutex); //wait for the condition
pthread_mutex_unlock(&mutex);
/*Do work*/
线程 3:
pthread_mutex_lock(&mutex); //mutex lock
while(!condition)
pthread_cond_wait(&condition, &mutex); //wait for the condition
pthread_mutex_unlock(&mutex);
/*Do work*/
我想知道这样的设置是否有效。假设线程 2 和 3 依赖于线程 1 需要处理的一些初始化选项。
【问题讨论】:
你可以让两个线程在相同的条件下等待,是的。当您调用pthread_cond_signal()
时,只有其中一个会被唤醒,但被唤醒的线程可能会再次发出信号以唤醒下一个等待的线程......或者您可以使用pthread_cond_broadcast()
来唤醒所有等待条件的线程。
【参考方案1】:
首先:如果你希望线程#1
唤醒线程#2
和#3
,它应该使用pthread_cond_broadcast
。
第二:设置有效(有广播)。线程#2
和#3
计划唤醒,它们将尝试重新获取互斥锁作为唤醒的一部分。其中一个会,另一个将不得不等待互斥锁再次解锁。所以线程#2
和#3
依次访问临界区(重新评估条件)。
【讨论】:
投反对票。没有解决while(!condition)
使用pthread_cond_t
类型的变量作为布尔值的严重问题,这是没有意义的。 pthread_cond_t
是一种不透明类型——它可以是任何东西,而且它不太可能具有用户可能期望的布尔值。其他答案解释了如何正确使用pthread_cond_wait()
。【参考方案2】:
如果我理解正确,您希望 thr#2 和 thr#3(“workers”)阻塞,直到 thr#1(“boss”)执行一些初始化。
您的方法几乎可行,但您需要广播而不是信号,并且缺少与条件变量分开的谓词变量。 (在您引用的问题中,谓词和条件变量的名称非常相似。)例如:
pthread_mutex_t mtx;
pthread_cond_t cv;
int initialized = 0; // our predicate of interest, signaled via cv
...
// boss thread
initialize_things();
pthread_mutex_lock(&mtx);
initialized = 1;
pthread_cond_broadcast(&cv);
pthread_mutex_unlock(&mtx);
...
// worker threads
pthread_mutex_lock(&mtx);
while (! initialized)
pthread_cond_wait(&cv, &mtx);
pthread_mutex_unlock(&mtx);
do_things();
这很常见,您可能希望将 mutex/cv/flag 组合成一个抽象。 (有关灵感,请参阅 Python 的 Event object。)POSIX barriers 这是同步线程的另一种方式:每个线程都等待直到所有线程“到达”。 pthread_once
是另一种方式,因为它只运行一次函数,无论有多少线程调用它。
【讨论】:
【参考方案3】:pthread_cond_signal
唤醒一个等待cond
变量的(随机)线程。如果你想唤醒所有等待这个cond
变量的线程,请使用pthread_cond_broadcast
。
【讨论】:
【参考方案4】:根据您在关键会话上所做的事情,除了先前答案中的解决方案之外,可能还有另一种解决方案。
假设thread1
首先执行(即它是创建者线程)并且假设thread2
和thread3
在关键会话中没有对共享资源执行任何写入操作。在这种情况下,pthread_cond_wait
是在实际上不需要时强制一个线程等待另一个线程。
您可以使用pthread_rwlock_t
类型的读写互斥锁。基本上thread1
执行写锁,因此其他线程在尝试获取读锁时将被阻塞。
这个锁的功能不言自明:
//They return: 0 if OK, error number on failure
int pthread_rwlock_init(pthread_rwlock_t *restrict rwlock,
const pthread_rwlockattr_t *restrict attr);
int pthread_rwlock_destroy(pthread_rwlock_t *rwlock);
int pthread_rwlock_rdlock(pthread_rwlock_t *rwlock);
int pthread_rwlock_wrlock(pthread_rwlock_t *rwlock);
int pthread_rwlock_unlock(pthread_rwlock_t *rwlock);
int pthread_rwlock_tryrdlock(pthread_rwlock_t *rwlock);
int pthread_rwlock_trywrlock(pthread_rwlock_t *rwlock);
当thread1
完成初始化时,它会解锁。其他线程将执行读锁,并且由于更多的读锁可以共存,它们可以同时执行。再次重申:如果您不在线程 2 和 3 中对共享资源执行任何写入,则这是有效的。
【讨论】:
以上是关于pthread_cond_wait() 同时唤醒两个线程的主要内容,如果未能解决你的问题,请参考以下文章
Linux C语言 pthread_cond_wait()pthread_cond_timedwait()函数(不允许cond被唤醒时产生竞争,所以需要和互斥锁搭配)