2017-10-19 174 views
0

假设我有两组线程。一个组的功能是将一个元素添加到数组中,另一个组的功能是如果数组包含相同的元素,则从数组中移除一个元素。规则是线程不能从数组中移除一个元素,如果它是空的并且它必须等待。监视器用于解决这个同步问题。调用condition_variable等待函数时线程如何等待?

考虑一个场景,其中所有线程同时启动,消费者线程首先锁定互斥锁,然后检查数组是否为空,条件为false,以便解锁互斥锁。然后生产者线程首先锁定互斥锁,添加一个元素并通知所有等待的线程并解锁互斥锁。问题是,等待的线程是否在得到通知后获得对互斥体的访问,并且等待的线程可以尝试移除该元素,或者互斥体再次释放,并且任何线程都可以再次锁定它,并且等待的线程不是条件失败后完成,但让我们说它被放回到线程池中。

+2

你最好展示一些(伪)代码,这很难理解你在问什么。 – Slava

回答

2

首先,让我们做一些事情说清楚(包括cppreference's page about std::condition_variable的精华):

消费者

消费者wait上使用以下步骤std::condition_variable -s:

  • 采集一个std::unique_lock<std::mutex>,与用于保护共享变量的相同互斥体
  • 执行wait,wait_for或wait_until。等待操作以原子方式释放互斥体并挂起线程的执行。
  • 当条件变量被通知时,超时到期或虚假唤醒发生,线程被唤醒,并且互斥体被自动重新获取。 线程应该检查条件,并且如果唤醒是虚假的,则继续等待

生产者

生产者notify相同std::condition_variable -s以下步骤:

  • 获取一个std ::互斥(通常通过标准:: lock_guard)
  • 执行修改同时锁持有
  • 执行notify_onenotify_all Ëstd::condition_variable(锁不需要追究通知)

回答

不等待的线程首先获取访问互斥它被通知,并等待线程可以尝试后要删除的元素

是,可能有多个消费者在相同条件下,和他们每个人可以消费的单个对象,这就是为什么每一个等待的线程应该防止SP使用额外的逻辑条件可以唤醒唤醒(请参阅消费者部分中的粗体文本)。的std::condition_variablewait方法甚至有已经包括它特定的原型:

template< class Predicate > 
void wait(std::unique_lock<std::mutex>& lock, Predicate pred); 

当消费者被唤醒时,它已经收购了锁!因此,如果满足条件(例如!queue->empty()),它可以安全地消耗。