调用condition_variable等待函数时线程如何等待?

时间:2017-10-19 19:26:59

标签: c++ multithreading synchronization

假设我有两组线程。一个组的功能是向数组添加元素,另一个组的功能是在数组包含相同元素时从数组中删除元素。规则是线程无法从数组中删除元素,如果它是空的并且必须等待。监视器用于解决此同步问题。

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

1 个答案:

答案 0 :(得分:2)

首先,让我们明确一些事情(包含cppreference's page about std::condition_variable 的精髓):

<强>消费者

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

  • 使用与保护共享变量
  • 相同的互斥锁获取std::unique_lock<std::mutex>
  • 执行wait,wait_for或wait_until。等待操作以原子方式释放互斥锁并暂停执行该线程。
  • 当通知条件变量,超时到期或发生虚假唤醒时,线程被唤醒,并且原子重新获取互斥锁。然后线程应该检查条件并在唤醒是虚假的情况下继续等待

<强>生产者

生产者notify遵循以下步骤std::condition_variable - s:

  • 获取std :: mutex(通常通过std :: lock_guard)
  • 在锁定时执行修改
  • notify_one执行notify_allstd::condition_variable(不需要保留锁定通知)

<强>答案

  

等待线程在收到通知后会先获取对互斥锁的访问权限,等待的线程可以尝试删除该元素

是的,可能有多个消费者处于相同的状态,并且每个消费者都可能消耗单个对象,这就是为什么每个等待的线程都应该使用额外的逻辑条件来防止虚假唤醒(参见粗体消费者部分的文字)。 wait的{​​{1}}方法甚至有一个特定的原型,已包含它:

std::condition_variable

当消费者醒来时,它已经获得了锁定!因此,如果满足条件(例如template< class Predicate > void wait( std::unique_lock<std::mutex>& lock, Predicate pred ); ),则可以安全地使用。