天天看点

C++多线程基础: 并发条件变量std::condition_variable

  wait

#include <iostream>              // std::cout
#include <thread>                // std::thread
#include <mutex>                 // std::mutex, std::unique_lock
#include <condition_variable>    // std::condition_variable

std::mutex mtx;              // 全局互斥锁.
std::condition_variable cv;  // 全局条件变量.
bool ready = true;           // 全局标志位.

void do_print_id(int id)
{
    std::unique_lock <std::mutex> lck(mtx);
    // 调用wait时mtx会被调用unlock解锁
    cv.wait(lck, [&](){
        // 启动线程或者被唤醒,这个函数会执行一次,如果返回是false继续阻塞等待
        std::cout << "wait: "<< id <<"\n";
        return ready;
    });
    std::cout << "thread " << id << '\n';
}

void go(bool is_ready)
{
    std::unique_lock <std::mutex> lck(mtx);
    ready = is_ready;
    cv.notify_all();
}

int main()
{
    std::thread threads[10];
    for (int i = 0; i < 10; ++i) {
        threads[i] = std::thread(do_print_id, i);
    }

    std::cout << "开始赛跑! \n";
    go(true);

    for (auto & th : threads) {
        th.join();
    }
        
    return 0;
}
           

 加入超时机制的wait, wait_util

#include <condition_variable>
#include <mutex>
#include <chrono>
#include <iostream>
#include <future>
#include <string>

std::condition_variable cv;
bool done = false;
std::mutex m;

void wait_loop()
{
    // 计算超时时刻的时间戳 (相当于第一次启动线程时开始计时)
    auto const timeout = std::chrono::steady_clock::now() + std::chrono::milliseconds(1000);
    std::unique_lock<std::mutex> lk(m);
    
    // cv.wait_until一直在阻塞且不返回值,直到:
    if (cv.wait_until(lk, timeout, []() {return done;})) {
        // 情况1: cv被notify_one或者notify_all通知后走到这个分支,但是done为false
        // 情况2: done为true后走到这个分支
        std::string done_str = (done == true ? "true" : "false");
        std::cout << "not timeout! work_done:" << done_str << "\n";
    } else {
        // 情况3: 超时后走到这个分支
        std::cout << "timeout!" << "\n";
    }
}

void do_the_work() {
    std::unique_lock<std::mutex> lk(m);
    done = true;
}

int main() {
    std::thread th = std::thread(wait_loop);
    // cv.notify_one();
    do_the_work();
    th.join();
    return 0;
}