C++ 併發編程(三):條件變量(Condition Variable)

條件變量(Condition Variable)的通常用法是:線程 A 等待某個條件並掛起,直到線程 B 設置了這個條件,並通知條件變量,而後線程 A 被喚醒。經典的「生產者-消費者」問題就能夠用條件變量來解決。ios

這裏等待的線程能夠是多個,通知線程能夠選擇一次通知一個(notify_one)或一次通知全部(notify_all)。this

示例修改自:http://en.cppreference.com/w/...線程

首先是頭文件:code

#include <iostream>
#include <string>
#include <thread>
#include <mutex>
#include <condition_variable>

而後是兩個線程共享的全局變量:get

std::mutex mutex;
std::condition_variable cv;
std::string data;
bool ready = false;  // 條件
bool processed = false;  // 條件

工做線程:string

void Worker() {
  std::unique_lock<std::mutex> lock(mutex);

  // 等待主線程發送數據。
  cv.wait(lock, [] { return ready; });

  // 等待後,繼續擁有鎖。
  std::cout << "工做線程正在處理數據..." << std::endl;
  // 睡眠一秒以模擬數據處理。
  std::this_thread::sleep_for(std::chrono::seconds(1));
  data += " 已處理";

  // 把數據發回主線程。
  processed = true;
  std::cout << "工做線程通知數據已經處理完畢。" << std::endl;

  // 通知前,手動解鎖以防正在等待的線程被喚醒後又當即被阻塞。
  lock.unlock();

  cv.notify_one();
}

主線程:it

int main() {
  std::thread worker(Worker);

  // 把數據發送給工做線程。
  {
    std::lock_guard<std::mutex> lock(mutex);
    std::cout << "主線程正在準備數據..." << std::endl;
    // 睡眠一秒以模擬數據準備。
    std::this_thread::sleep_for(std::chrono::seconds(1));
    data = "樣本數據";
    ready = true;
    std::cout << "主線程通知數據已經準備完畢。" << std::endl;
  }
  cv.notify_one();

  // 等待工做線程處理數據。
  {
    std::unique_lock<std::mutex> lock(mutex);
    cv.wait(lock, [] { return processed; });
  }
  std::cout << "回到主線程,數據 = " << data << std::endl;

  worker.join();

  return 0;
}

輸出:io

主線程正在準備數據...
主線程通知數據已經準備完畢。
工做線程正在處理數據...
工做線程通知數據已經處理完畢。
回到主線程,數據 = 樣本數據 已處理

下面是一些說明。class

與條件變量搭配使用的「鎖」,必須是 unique_lock,不能用 lock_guard。這個前面文章中已有說明。thread

等待前先加鎖。等待時,若是條件不知足,wait 會原子性地解鎖並把線程掛起。

條件變量被通知後,掛起的線程就被喚醒,可是喚醒也有多是假喚醒,或者是由於超時等異常狀況,因此被喚醒的線程仍要檢查條件是否知足,因此 wait 是放在條件循環裏面。cv.wait(lock, [] { return ready; }); 至關於:while (!ready) { cv.wait(lock); }

相關文章
相關標籤/搜索