1. 程式人生 > 其它 >C++11——多執行緒程式設計7

C++11——多執行緒程式設計7

條件變數是一種用於在2個執行緒之間進行信令的事件,一個執行緒可以等待它得到訊號,其他的執行緒可以給它發訊號。
在c++11中,條件變數需要標頭檔案:

#include <condition_variable>

同時,條件變數還需要一個mutex鎖

條件變數實際上是如何工作的,

  • 執行緒 1 呼叫等待條件變數,該變數在內部獲取互斥鎖並檢查是否滿足所需條件。
  • 如果不是,則它釋放鎖並等待條件變數收到訊號(執行緒被阻塞)。條件變數的 wait() 函式以原子方式提供這兩種操作
  • 另一個執行緒,即執行緒 2,在滿足條件時向條件變數發出訊號
  • 旦條件變數得到訊號,等待它的執行緒 1 就會恢復。
    然後它再次獲取互斥鎖並檢查與條件變數關聯的條件是否實際滿足或者是否是上級呼叫。如果有多個執行緒在等待,notify_one 將只解除一個執行緒的阻塞。
  • 如果是上級呼叫,則它再次呼叫 wait() 函式。

條件變數的主要成員函式是:
Wait()

他使得當前程序阻塞 知道條件變數得到訊號或者是被虛假喚醒

它原子性地釋放附加的mutex,阻塞當前執行緒,並將其新增到等待當前條件變數物件的執行緒列表中當某執行緒在同樣的條件變數上呼叫notify_one() 或者 notify_all(),執行緒將被解除阻塞
這種行為也可能是虛假的,因此,解除阻塞後,需要再次檢查條件;
一個回撥函式會傳給該函式,呼叫它來檢查其是否是虛假呼叫

,還是確實滿足了真實條件;
當執行緒解除阻塞後wait()函式獲取mutex鎖,並檢查條件是否滿足,如果條件不滿足,則再次原子性地釋放附加的mutex,阻塞當前執行緒,並將其新增到等待當前條件變數物件的執行緒列表中

notify_one()
如果所有執行緒都在等待相同的條件變數物件,那麼notify_one會取消阻塞其中一個等待執行緒。

notify_all()
如果所有執行緒都在等待相同的條件變數物件,那麼notify_all會取消阻塞所有的等待執行緒。
如何處理第六節討論的帶有條件變數的多執行緒情景呢?
code:

#include <iostream>
#include <thread>
#include 
<functional> #include <mutex> #include <condition_variable> using namespace std::placeholders; class Application { std::mutex m_mutex; std::condition_variable m_condVar; bool m_bDataLoaded; public: Application() { m_bDataLoaded = false; } void loadData() { //使該執行緒sleep 1秒 std::this_thread::sleep_for(std::chrono::milliseconds(1000)); std::cout << "Loading Data from XML" << std::endl; //鎖定資料 std::lock_guard<std::mutex> guard(m_mutex); //flag設為true,表明資料已載入 m_bDataLoaded = true; //通知條件變數 m_condVar.notify_one(); } bool isDataLoaded() { return m_bDataLoaded; } void mainTask() { std::cout << "Do some handshaking" << std::endl; //獲取鎖 std::unique_lock<std::mutex> mlock(m_mutex); //開始等待條件變數得到訊號 //wait()將在內部釋放鎖,並使執行緒阻塞 //一旦條件變數發出訊號,則恢復執行緒並再次獲取鎖 //然後檢測條件是否滿足,如果條件滿足,則繼續,否則再次進入wait m_condVar.wait(mlock, std::bind(&Application::isDataLoaded, this)); std::cout << "Do Processing On loaded Data" << std::endl; } }; int main() { Application app; std::thread thread_1(&Application::mainTask, &app); std::thread thread_2(&Application::loadData, &app); thread_2.join(); thread_1.join(); return 0; }