我想问一下,使用1个与2个互斥量相关的条件变量是否可以进行2种数据更新。
基本上,我有thread1和thread2。 Thread1可以等待2种数据更新,因此它有2个互斥,每个一个。 (我知道我可以使用一个互斥量用于所有这些数据,但这不是这个问题的重点,对吧?)我当然不希望它等待data1而data2已经可用,所以它只有1个条件变量。而thread2将提供data1和data2。问题是在thread2中,我不知道thread1现在是在等待data1还是data2,或者根本不在等待。
伪代码如下所示:
global data:
cond_var
mutex1
data1
mutex2
data2
thread1:
while true
lock1.lock(mutex1)
if data1 is not available
cond_var.wait(lock1)
if data1 is available
process data1
lock1.unlock()
lock2.lock(mutex2)
if data2 is not available
cond_var.wait(lock2)
if data2 is available
process data2
lock2.unlock()
thread2:
func1:
lock1.lock(mutex1)
update data1
cond_var.notify_all()
lock1.unlock()
func2:
lock2.lock(mutex2)
update data2
cond_var.notify_all()
lock2.unlock()
外界将调用func1或func2来更新数据。 当调用func1或func2时,它将发出cond_var信号,无论是在lock1还是lock2中。 cond_var的等待不会被while包围,所以如果在lock1上唤醒cond_var但data2可用,则thread1将继续处理data2。
实际的实现是通过boost :: thread,因为我的测试平台是Linux,所以boost :: thread应该通过pthread实现。
在几乎所有关于条件变量的教程和文档中,它只与1个互斥量相关联。所以我很想知道上面的程序是否可以使用,或者是否存在根本缺陷。
答案 0 :(得分:1)
没关系。
Boost.Thread实现了C ++ 11线程库(它在v1.50之前有一些差异但现在非常接近)并且该线程库在概念上接近Pthread模型,但是使用不同的API,所以我们可以看看这些规格的答案。
C ++ 11标准中的规则是:
要求:
lock.owns_lock()
为true
且lock.mutex()
被调用线程锁定,并且 - 没有其他线程正在等待此condition_variable
对象或
-lock.mutex()
为所有并发等待(lock
,via wait
或wait_for
个线程提供的每个wait_until
参数返回相同的值。
在您的情况下,互斥锁被正确锁定,并且只有一个线程在condvar上等待,因此满足条件。
POSIX中的规则是等效的,但措辞不同:
在同一条件变量上使用多个互斥锁对并发
pthread_cond_timedwait()
或pthread_cond_wait()
运算的影响未定义;也就是说,当一个线程等待条件变量时,一个条件变量被绑定到一个唯一的互斥锁,并且这个(动态)绑定将在等待返回时结束。
同样,您没有并发等待操作。
通常,只要您不等待同时使用不同的互斥锁 ,就可以使用带有不同互斥锁的condvar。在等待condvar时,你将它与互斥锁和谓词(“条件”)相关联,所以当POSIX描述时,condvar和互斥锁被“绑定”在一起,并且任何condvar一次不能绑定到多个互斥锁。原因是当一个condvar从等待中唤醒时它必须重新获取它所关联的互斥锁,如果不同的线程使用它与不同的互斥锁,它可能会在错误的线程中重新锁定错误的互斥锁,从而导致混乱。一个线程会觉得它已经重新锁定了它等待的互斥锁,但它实际上锁定了一个不同的互斥锁,也许它没有任何引用,所以永远无法解锁。死锁和/或未定义的行为和狮子,老虎和熊,哦,我的。
在你的情况下没有并发等待,所以没问题。如果您有多个线程在等待,则需要确保两个线程都使用相同的互斥锁进行任何给定的等待...这将是困难的,因为您需要一些额外的同步,因此使用它会更简单两个condvars。