標籤:blog 對象 ack 通知 oid capacity 技術分享 comm ace
條件變數
如果線程之間執行順序上有依賴關係,可使用條件變數(Condition variables)。
可以到boost官網中參考條件變數(Condition variables)的使用。
條件變數必須和互斥量配合使用,等待另一個線程重某個事件的發生(滿足某個條件),然後線程才能繼續執行。
共有兩種條件變數對象condition_variable, condition_variable_any,一般情況下使用condition_variable_any。
條件變數的使用方式:
擁有條件變數的線程先鎖定互斥量,然後迴圈檢查某個條件,如果條件不滿足,那麼就調用條件變數的成員函數wait()等待直到條件滿足。其他線程處理條件變數要求的條件,當條件滿足時調用它的成員函數notify_one()或者notify_all(),以通知一個或者所有正在等待條件的變數的線程停止等待繼續執行。
例子:生產--消費模型。
緩衝區buffer使用了兩個條件變數cond_put和cond_get,分別用於處理put動作和get動作,如果緩衝區滿則cond_put持續等待,當cond_put得到通知 (緩衝區不滿)時線程寫入資料,然後通知cond_get條件變數可以擷取資料。cond_get的處理流程與cond_put類似。
C++代碼
- #include <boost/thread.hpp>
- #include <boost/thread/mutex.hpp>
-
- #include <iostream>
- #include <stack>
-
- using namespace std;
-
- boost::mutex io_mu;
-
- class buffer
- {
- private:
- boost::mutex mu; // 互斥量,配合條件變數使用
- boost::condition_variable_any cond_put; // 寫入條件變數
- boost::condition_variable_any cond_get; // 讀取條件變數
-
- stack<int> stk; // 緩衝區對象
- int un_read, capacity;
- bool is_full() // 緩衝區滿判斷
- {
- return un_read == capacity;
- }
- bool is_empty() // 緩衝區空判斷
- {
- return un_read == 0;
- }
-
- public:
- buffer(size_t n) : un_read(0), capacity(n){} // 建構函式
- void put(int x) // 寫入資料
- {
- { // 開始一個局部域
- boost::mutex::scoped_lock lock(mu); //鎖定互斥量
- while ( is_full() ) // 檢查緩衝區是否滿
- {
- { // 局部域,鎖定cout輸出一條資訊
- boost::mutex::scoped_lock lock(io_mu);
- cout << "full waiting..." << endl;
- }
- cond_put.wait(mu); // 條件變數等待
- } // 條件變臉滿足,停止等待
- stk.push(x); // 壓棧,寫入資料
- ++un_read;
- } // 解鎖互斥量,條件變數的通知不需要互斥量鎖定
- cond_get.notify_one(); // 通知可以讀取資料
- }
-
- void get(int *x) // 讀取資料
- {
- { // 局部域開始
- boost::mutex::scoped_lock lock(mu); // 鎖定互斥量
- while (is_empty()) // 檢查緩衝區是否空
- {
- {
- boost::mutex::scoped_lock lock(io_mu);
- cout << "empty waiting..." << endl;
- }
- cond_get.wait(mu); // 條件變數等待
- }
- --un_read;
- *x = stk.top(); // 讀取資料
- stk.pop(); // 彈棧
- }
- cond_put.notify_one(); // 通知可以寫入資料
- }
- };
-
- buffer buf(5); // 一個緩衝區對象
- void producter(int n) // 生產者
- {
- for (int i = 0; i < n; ++i)
- {
- {
- boost::mutex::scoped_lock lock(io_mu);
- cout << "put " << i << endl;
- }
- buf.put(i); // 寫入資料
- }
- }
-
- void consumer(int n) // 消費者
- {
- int x;
- for (int i = 0; i < n; ++i)
- {
- buf.get(&x); // 讀取資料
- boost::mutex::scoped_lock lock(io_mu);
- cout << "get " << x << endl;
- }
- }
-
- int main()
- {
- boost::thread t1(producter, 20); // 一個生產者線程
- boost::thread t2(consumer, 10); // 兩個消費者線程
- boost::thread t3(consumer, 10);
-
- t1.join();
- t2.join();
- t3.join();
-
- return 0;
- }
運行結果:
empty waiting...
put 0
empty waiting...
put 1
put 2
get 1
get 2
get 0
empty waiting...
empty waiting...
put 3
put 4
put 5
put 6
put 7
get 6
get 7
get 5
get 4
get 3
empty waiting...
put 8
empty waiting...
put 9
put 10
put 11
get 9
get 11
get 8
empty waiting...
put 12
put 13
put 14
put 15
put 16
put 17
full waiting...
get 10
get 16
put 18
full waiting...
get 17
get 15
get 14
get 13
get 12
get 18
empty waiting...
put 19
get 19
C++ boost thread學習(二)