C++ 调用条件变量wait函数时,线程如何等待?

C++ 调用条件变量wait函数时,线程如何等待?,c++,multithreading,synchronization,C++,Multithreading,Synchronization,假设我有两组线程。一个组的功能是向数组中添加元素,另一个组的功能是在数组包含相同元素时从数组中删除元素。规则是,如果元素为空且必须等待,则线程无法从数组中删除该元素。监视器用于解决此同步问题 考虑一个场景,其中所有线程同时启动,使用者线程首先锁定互斥锁,然后检查数组是否为空,条件是否为false,从而解锁互斥锁。然后,生产者线程首先锁定互斥锁,添加元素并通知所有等待的线程并解锁互斥锁。问题是,等待线程是否在收到通知后首先获得对互斥体的访问权,并且等待线程可以尝试删除该元素,或者互斥体再次空闲,任

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


考虑一个场景,其中所有线程同时启动,使用者线程首先锁定互斥锁,然后检查数组是否为空,条件是否为false,从而解锁互斥锁。然后,生产者线程首先锁定互斥锁,添加元素并通知所有等待的线程并解锁互斥锁。问题是,等待线程是否在收到通知后首先获得对互斥体的访问权,并且等待线程可以尝试删除该元素,或者互斥体再次空闲,任何线程都可以偶然再次锁定它,并且等待线程在条件失败后未完成,但假设它被放回线程池中。

首先,让我们把一些事情弄清楚(包括本质):

消费者

消费者使用以下步骤在
std::condition_variable
-s上等待

  • 在用于保护共享变量的同一互斥体上获取
    std::unique_lock
  • 执行等待、等待或等待。wait操作以原子方式释放互斥体并挂起线程的执行
  • 当通知条件变量、超时过期或发生虚假唤醒时,线程被唤醒,互斥锁被原子地重新获取。然后,如果唤醒是虚假的,线程应该检查条件并继续等待
制作人

生产者按照以下步骤通知相同的
std::condition\u变量
-s:

  • 获取std::mutex(通常通过std::lock\u-guard)
  • 在保持锁的同时执行修改
  • std::condition\u变量
    上执行
    notify_one
    notify_all
    (不需要为通知而保持锁)
回答

等待线程是否在收到通知后首先获得对互斥体的访问权,并且等待线程是否可以尝试删除该元素

是的,在相同的条件下可能有多个使用者,并且每个使用者都可能使用单个对象,这就是为什么每个等待线程都应该使用附加的逻辑条件来防止虚假唤醒(请参阅使用者部分中的粗体文本)。
std::condition_variable
wait
方法甚至有一个已经包含它的特定原型:

template< class Predicate >
void wait( std::unique_lock<std::mutex>& lock, Predicate pred );
模板
无效等待(std::unique_lock&lock,谓词pred);

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

首先,让我们澄清一些事情(包括以下内容):

消费者

消费者使用以下步骤在
std::condition_variable
-s上等待

  • 在用于保护共享变量的同一互斥体上获取
    std::unique_lock
  • 执行等待、等待或等待。wait操作以原子方式释放互斥体并挂起线程的执行
  • 当通知条件变量、超时过期或发生虚假唤醒时,线程被唤醒,互斥锁被原子地重新获取。然后,如果唤醒是虚假的,线程应该检查条件并继续等待
制作人

生产者按照以下步骤通知相同的
std::condition\u变量
-s:

  • 获取std::mutex(通常通过std::lock\u-guard)
  • 在保持锁的同时执行修改
  • std::condition\u变量
    上执行
    notify_one
    notify_all
    (不需要为通知而保持锁)
回答

等待线程是否在收到通知后首先获得对互斥体的访问权,并且等待线程是否可以尝试删除该元素

是的,在相同的条件下可能有多个使用者,并且每个使用者都可能使用单个对象,这就是为什么每个等待线程都应该使用附加的逻辑条件来防止虚假唤醒(请参阅使用者部分中的粗体文本)。
std::condition_variable
wait
方法甚至有一个已经包含它的特定原型:

template< class Predicate >
void wait( std::unique_lock<std::mutex>& lock, Predicate pred );
模板
无效等待(std::unique_lock&lock,谓词pred);
当消费者醒来时,它已经获得了锁!因此,如果满足条件(例如
!queue->empty()
),它可以安全地消费。

您最好显示一些(伪)代码,很难理解您的要求。您最好显示一些(伪)代码,很难理解您的要求。