3

我想问一下是否可以使用与 2 个互斥锁关联的 1 个条件变量来进行 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 包围,所以如果 cond_var 在 lock1 上被唤醒,但 data2 可用,thread1 会继续处理 data2。

实际的实现是通过 boost::thread,由于我的测试平台是 Linux,所以 boost::thread 应该通过 pthread 实现。

在我阅读的几乎所有关于条件变量的教程和文档中,它只与 1 个互斥锁相关联。所以我很想知道上面的程序是否可以使用,或者根本上存在缺陷。

4

1 回答 1

1

还行吧。

Boost.Thread 实现了 C++11 线程库(它在 v1.50 之前有一些差异,但现在非常接近)并且该线程库在概念上接近 Pthread 模型,但使用不同的 API,所以我们可以看看那些答案的规格。

C++11 标准中的规则是:

Requires: lock.owns_lock() istrue并且lock.mutex()被调用线程锁定,并且要么
- 没有其他线程在此condition_variable对象上等待,要么
-为所有并发等待的 ( 、 或 ) 线程提供的每个参数返回相同的lock.mutex()值。lockvia waitwait_forwait_until

在您的情况下,互斥锁已正确锁定,并且只有一个线程在 condvar 上等待,因此满足条件。

POSIX 中的规则是等价的,但措辞不同:

对同一条件变量使用多个互斥体进行并发pthread_cond_timedwait()或操作的效果是不确定的;pthread_cond_wait()也就是说,当线程等待条件变量时,条件变量将绑定到唯一的互斥体,并且此(动态)绑定将在等待返回时结束。

同样,您没有并发等待操作。

一般来说,只要您从不等待同时使用不同的互斥锁,就可以使用具有不同互斥锁的 condvar. 当等待一个 condvar 时,您将它与一个互斥锁和一个谓词(“条件”)相关联,正如 POSIX 描述的那样,condvar 和互斥锁被“绑定”在一起,任何一个 condvar 一次不得绑定到多个互斥锁. 原因是当 condvar 从等待中唤醒时,它必须重新获取与其关联的互斥锁,如果不同的线程已将它与不同的互斥锁一起使用,它可能会将错误的互斥锁重新锁定在错误的线程中,从而导致混乱。一个线程会醒来,以为它已经重新锁定了它等待的互斥锁,但它实际上锁定了另一个互斥锁,也许它没有任何引用,因此永远无法解锁。僵局和/或未定义的行为以及狮子、老虎和熊,哦,我的。

在您的情况下,没有并发等待,所以没问题。如果您有多个线程在等待,则需要确保两个线程在任何给定的等待中都使用相同的互斥锁...这将很困难,因为您需要一些额外的同步,因此使用起来会更简单两个条件。

于 2012-10-18T09:50:46.280 回答