C++11之条件变量 condition_variable

概念简介

条件变量(condition_variable)是一种同步原语,用于线程之间的协调。它允许一个或多个线程一起等待另一个线程的通知。条件变量依赖于互斥量(mutex),它被用来保护等待条件变量的共享数据,并在条件满足时通知等待的线程。

线程通过持有互斥锁来进入等待状态并等待从其它线程中获得信号释放,该线程可以获取到mutex。当其它线程以notify_one或notify_all的方式发出通知,等待线程被唤醒开始尝试重新获取互斥锁。这意味着只有在持有互斥锁时才可以进行等待或接收条件变量信号

当某个线程调用条件变量的wait方法时,它会释放占用的互斥锁lock,因此,等待线程不会阻塞在互斥锁上,同时允许其他线程使用该锁。然后该线程阻塞,开始等待被notify_onenotify_all唤醒。在唤醒之后,线程会重新尝试获得互斥锁lock。如果互斥锁无法获得,则该线程将阻塞等待互斥量变得可用。如果可以获得互斥锁,则等待线程继续执行,并处理条件变量得到的通知。

锁是为了保护临界资源不被随意访问,条件变量是多线程之间相互通知,如资源是否可用的一种通信手段,两种机制往往配合使用;想象一下,如果没有条件变量的通知机制,那么等待线程就不能阻塞且让出CPU时间片的等待,而是定时或者死循环的等待,对整个系统资源来说,无非是一种浪费。

条件变量原型以及常用接口

lass condition_variable
  {
  public:

    condition_variable() noexcept;
    ~condition_variable() noexcept;

    condition_variable(const condition_variable&) = delete;
    condition_variable& operator=(const condition_variable&) = delete;

    void
    notify_one() noexcept;

    void
    notify_all() noexcept;

    void
    wait(unique_lock<mutex>& __lock) noexcept;

    template<typename _Duration>
      cv_status
      wait_until(unique_lock<mutex>& __lock,
		 const chrono::time_point<__clock_t, _Duration>& __atime)
      { return __wait_until_impl(__lock, __atime); }

    template<typename _Clock, typename _Duration>
      cv_status
      wait_until(unique_lock<mutex>& __lock,
		 const chrono::time_point<_Clock, _Duration>& __atime)template<typename _Clock, typename _Duration, typename _Predicate>
      bool
      wait_until(unique_lock<mutex>& __lock,
		 const chrono::time_point<_Clock, _Duration>& __atime,
		 _Predicate __p)
      {
	while (!__p())
	  if (wait_until(__lock, __atime) == cv_status::timeout)
	    return __p();
	return true;
      }

    template<typename _Rep, typename _Period>
      cv_status
      wait_for(unique_lock<mutex>& __lock,
	       const chrono::duration<_Rep, _Period>& __rtime)template<typename _Rep, typename _Period, typename _Predicate>
      bool
      wait_for(unique_lock<mutex>& __lock,
	       const chrono::duration<_Rep, _Period>& __rtime,
	       _Predicate __p)
      {
		//......
	return wait_until(__lock, __steady_clock_t::now() + __reltime,
			  std::move(__p));
      }

  private:
    template<typename _Dur>
      cv_status
      __wait_until_impl(unique_lock<mutex>& __lock,
			const chrono::time_point<__clock_t, _Dur>& __atime)};

常用接口简介:

  1. void wait(unique_lock<mutex>& __lock), 调用该函数的线程,主动释放锁,然后阻塞,等待条件变量通知,如果被唤醒,将重新去获得__lock锁,就可以正确进行临界资源的访问;
  2. notify_one() / notify_all()唤起,通知一个或者所有等待阻塞在当前条件变量上的线程,通知前当前线程应该释放自己占用的锁,以便得到通知的线程能拿到锁访问临界资源;
    template<typename _Predicate>
      void
      wait(unique_lock<mutex>& __lock, _Predicate __p)
      {
		while (!__p())
	  		wait(__lock);
      }
  1. 如上接口void wait(unique_lock<mutex>& __lock, _Predicate __p),除了含有一个unique_lock锁对象参数,还有一个返回值为bool的表达式参数。该wait函数中循环的判断检查表达式P的返回值是否为真,如果为真,将尝试获取锁,获取成功将继续向下执行,否则将阻塞等待互斥锁可用;如果返回的是false,会释放锁,重新阻塞;

举个例子,一个线程访问一个消息队列, 若不为空,线程将可以获取锁,进行下一步操作

cv.wait(lock, [](){ return !msgQueue.empty(); })
  1. bool wait_for(//...) 阻塞当前线程,直到条件变量被唤醒,或超时返回
  2. bool wait_until(//...) for是一段时长,until是一个时间点
  3. 静态函数void notify_all_at_thread_exit(condition_variable&, unique_lock<mutex>) ,一般在线程的入口函数调用,注册其所持有的锁以及条件变量,从而可以在线程退出时释放锁并且通知等待在该条件变量上线程,其他线程可以通过条件变量收到通知并获取锁访问临界区。
//在一个线程方法中调用该方法,
{
std::unique_lock<std::mutex> lk(m);
std::notify_all_at_thread_exit(cond, std::move(lk), my_id); 
// ...  做业务  访问临界区代码
//右括号退出前,释放锁,通知其他wait在当前cond上的线程
}

其他等待的线程:

{
 std::unique_lock<std::mutex> lk(m);
 cond.wait(lk); // 阻塞,等待条件变量通知
  // ... 做业务 然后退出
}

示例 生产者消费者m

生产者消费者队列

  • 1
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
condition_variable_any是C++11标准引入的一个类,它是condition_variable的一个通用化版本。它可以与任何实现了BasicLockable概念的锁对象一起使用,比如std::mutex和std::shared_lock。condition_variable_any的构造函数可以通过调用`condition_variable_any()`来创建一个对象。它还提供了一些成员函数,比如wait()用于等待条件满足,notify_one()用于通知一个正在等待的线程,notify_all()用于通知所有正在等待的线程。在使用condition_variable_any时,需要手动加锁和解锁,并且要注意遵循特定的使用约定。通过使用condition_variable_any,我们可以更加灵活地处理条件变量的等待和通知。<span class="em">1</span><span class="em">2</span><span class="em">3</span> #### 引用[.reference_title] - *1* *3* [c++11 多线程支持 条件变量condition_variable)(一)](https://blog.csdn.net/qq_40788199/article/details/126435885)[target="_blank" data-report-click={"spm":"1018.2226.3001.9630","extra":{"utm_source":"vip_chatgpt_common_search_pc_result","utm_medium":"distribute.pc_search_result.none-task-cask-2~all~insert_cask~default-1-null.142^v92^chatsearchT0_1"}}] [.reference_item style="max-width: 50%"] - *2* [C++ 多线程同步condition_variable_any的用法](https://blog.csdn.net/weixin_43369786/article/details/129326689)[target="_blank" data-report-click={"spm":"1018.2226.3001.9630","extra":{"utm_source":"vip_chatgpt_common_search_pc_result","utm_medium":"distribute.pc_search_result.none-task-cask-2~all~insert_cask~default-1-null.142^v92^chatsearchT0_1"}}] [.reference_item style="max-width: 50%"] [ .reference_list ]

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值