c++ 条件变量使用详解 wait

编程入门 行业动态 更新时间:2024-10-23 07:15:27

c++ 条件<a href=https://www.elefans.com/category/jswz/34/1771380.html style=变量使用详解 wait"/>

c++ 条件变量使用详解 wait

c++ 条件变量使用详解

std::condition_variable

  • 线程间同步的条件变量类。允许一个或多个线程在满足特定条件之前等待,同时允许其他线程通知、唤醒等待的线程。

成员函数

  • notify_one:通知一个等待的线程。
  • notify_all:通知所有等待的线程。
  • wait:阻塞当前线程,直到条件变量被唤醒。
  • wait_until:阻塞当前线程,直到条件变量被唤醒,或直到抵达指定时间点。
  • wait_for:阻塞当前线程,直到条件变量被唤醒,或直到指定时限时长后。

使用方法

  • 对于修改条件后通知其他线程的线程:
    • 获得 std::mutex,通常使用 std::lock_guard;
    • 在成功获得锁后,修改条件;
    • 使用 notify_one 或 notify_all 唤醒等待的线程;
  • 对于等待唤醒的线程:
    • 获得 std::mutex,通常使用 std::unique_lock;
    • 使用 wait,wait_for,wait_until 等待唤醒,此时线程释放互斥,并进入阻塞;
    • 被其他线程唤醒,被虚假唤醒或者等待超时,线程自动重获得互斥,此时应检查条件是否成立,若不成立,则继续等待或者返回;

虚假唤醒

  • 指线程在等待期间,重新获得互斥,而这一行为却不来源于其他任何线程的通知,则称之为虚假唤醒。
  • 按照 c++ 标准规定,虚假唤醒出现的数量以及比率都不确定。

notify_one notify_all

  • 使用注意:在唤醒其他线程时,通知线程一般无需持有互斥,因为被唤醒线程醒来后,一旦不能立即获得互斥,将会再次阻塞。

wait

  • 函数原型:

    void wait(std::unique_lock<std::mutex>& lock);
    // 若发生虚假唤醒,wait 之后的代码将会被执行template<class Predicate>
    void wait(std::unique_lock<std::mutex>& lock, Predicate pred);
    // 相当于
    while (!pred()) {wait(lock);
    }
    // 可以避免虚假唤醒
    
    • lock:互斥体,必须被当前线程锁定;
    • pred:返回 ​false,则继续等待。其签名为 bool pred();
  • 使当前线程阻塞直至条件变量被通知,或虚假唤醒发生,可选地循环直至满足 pred。

wait_until

  • 函数原型:

    template<class Clock, class Duration>
    std::cv_status wait_until(std::unique_lock<std::mutex>& lock,const std::chrono::time_point<Clock, Duration>& timeout_time);
    // 若发生虚假唤醒,如果未超时,则返回 std::cv_status::no_timeout,超时则返回 std::cv_status::timeouttemplate<class Clock, class Duration, class Pred>
    bool wait_until(std::unique_lock<std::mutex>& lock,const std::chrono::time_point<Clock, Duration>& timeout_time,Pred pred);
    // 相当于
    while (!pred()) {if (wait_until(lock, timeout_time) == std::cv_status::timeout) {return pred();}
    }
    return true;
    // 可以避免虚假唤醒
    
    • lock:互斥体,必须被当前线程锁定;
    • timeout_time:表示停止等待时间的 std::chrono::time_point 类型对象;
    • pred:返回 ​false,则继续等待。其签名为 bool pred();
  • 使当前线程阻塞直至条件变量被通知、抵达指定时间或虚假唤醒发生,可选的循环直至满足 pred。

  • 使用注意:时钟最好使用稳定时钟,即计时速率恒定且无法调整的时钟。

wait_for

  • 函数原型:

    template<class Rep, class Period>
    std::cv_status wait_for(std::unique_lock<std::mutex>& lock,const std::chrono::duration<Rep, Period>& rel_time);
    // 若发生虚假唤醒,如果未超时,则返回 std::cv_status::no_timeout,超时则返回 std::cv_status::timeouttemplate<class Rep, class Period, class Predicate>
    bool wait_for(std::unique_lock<std::mutex>& lock,const std::chrono::duration<Rep, Period>& rel_time,Predicate pred);
    // 相当于
    wait_until(lock, std::chrono::steady_clock::now() + rel_time, std::move(pred));
    
    • lock:互斥体,必须被当前线程锁定;
    • rel_time:表示等待所耗的最大时间的 std::chrono::duration 类型对象。rel_time 必须足够小,以在加到 std::chrono::steady_clock::now() 时不溢出;
    • pred:返回 ​false,则继续等待。其签名为 bool pred();
  • 使当前线程阻塞直至条件变量被通知、抵达指定时间或虚假唤醒发生,可选的循环直至满足 pred。

  • 由于操作系统调度或资源争议,此函数可能阻塞长于 rel_time。

示例代码

  • 线程1修改变量,线程2等待变量被修改。

    #include <iostream>
    #include <condition_variable>
    #include <thread>
    #include <chrono>using namespace std::chrono_literals;int i = 0;
    bool changed{false};
    std::condition_variable cv;
    std::mutex cv_m;void wait()
    {std::unique_lock<std::mutex> lk(cv_m);// std::chrono_literals::100ms, c++14 引入if (cv.wait_for(lk, 100ms, [](){return changed;})) {printf("finished waiting, i is %d\n", i);} else {printf("wait timeout, i is %d\n", i);}
    }void notify()
    {{std::this_thread::sleep_for(50ms);std::lock_guard<std::mutex> lk(cv_m);i = 10;changed = true;printf("change finished\n");}cv.notify_one();
    }int main()
    {std::thread t1(notify);std::thread t2(wait);t1.join();t2.join();return 0;
    }
    

更多推荐

c++ 条件变量使用详解 wait

本文发布于:2023-11-16 07:27:46,感谢您对本站的认可!
本文链接:https://www.elefans.com/category/jswz/34/1614671.html
版权声明:本站内容均来自互联网,仅供演示用,请勿用于商业和其他非法用途。如果侵犯了您的权益请与我们联系,我们将在24小时内删除。
本文标签:变量   详解   条件   wait

发布评论

评论列表 (有 0 条评论)
草根站长

>www.elefans.com

编程频道|电子爱好者 - 技术资讯及电子产品介绍!