天天看點

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;
}