[C++11 併發程式設計] 11
上一節,我們瞭解瞭如何對執行緒之間的共享資源進行保護的方法。但是,有些時候,我們需要線上程之間進行同步操作。一個執行緒等待另一個執行緒完成某項工作後,再繼續自己的工作。比如,某個執行緒需要等待一個訊息,或者某個條件變成true。接下來幾節,我們會看到如何使用C++標準庫來做到執行緒間同步。
等待另一個執行緒完成的方法有如下幾種:
- 一個執行緒不停地查詢某個被mutex保護的貢獻資料區中的標誌的狀態。另一個執行緒在完成工作後,設定這個標誌。這種方法十分浪費資源,因為第一個執行緒需要不停的執行而佔用CPU。並且,當第一個執行緒鎖定mutex後,第二個執行緒即使完成了工作,也無法立即設定這個標誌,因為mutex被第一個執行緒鎖定了。
- 第二種方法是在每次檢查表之後,執行一定時間的休眠。
bool flag;
std::mutex m;
void wait_for_flag()
{
std::unique_lock<std::mutex> lk(m);
while(!flag)
{
lk.unlock(); // 1 解鎖互斥量
std::this_thread::sleep_for(std::chrono::milliseconds(100)); // 2 休眠100ms
lk.lock(); // 3 再鎖互斥量
}
}
比如,上面得了例子,解鎖mutex後,先睡眠100ms,在再次鎖定mutex。這樣做,比第一種方法要好一點,但是睡眠時間長短很難確定。短了,就跟沒有休眠一樣,很浪費CPU資源。長了,可能這個執行緒等待的另一個執行緒已經完成了操作,這個執行緒都還在休眠。可能會導致類似掉幀之類的問題。
- 第三種方法是我們所推薦的,使用C++標準庫提供的機制-條件變數來實現等待操作。條件變數關聯到某種事件或者其它條件,一個或多個執行緒可以通過這個變數來等待條件的發生。某個執行緒在發現該條件滿足後,可以通知其它因等待該條件而掛起的執行緒,喚醒它們讓它們繼續執行。
程式執行效果如下:輸入a,data_preparation_thread喚醒data_processing_thread,輸入q,data_processing_thread再次被data_preparation_thread喚醒,處理資料之後,程式結束。#include <iostream> #include <mutex> #include <condition_variable> #include <thread> #include <queue> static bool more = true; bool more_data_to_prepare() { return more; } struct data_chunk { char m_data = 'q'; data_chunk(char c) : m_data(c) { } }; data_chunk prepare_data() { std::cout << "data_preparation_thread prepare_data"<< std::endl; char x = 'q'; std::cin >> x; if (x == 'q') { more = false; } return data_chunk(x); } void process(data_chunk& data) { std::cout << "process data: " << data.m_data << std::endl; } bool is_last_chunk(data_chunk& data) { if (data.m_data == 'q') { return true; } return false; } std::mutex mut; std::queue<data_chunk> data_queue; // 用於執行緒間通訊的佇列 std::condition_variable data_cond; void data_preparation_thread() { while(more_data_to_prepare()) { std::cout << "data_preparation_thread while" << std::endl; data_chunk const data=prepare_data(); std::lock_guard<std::mutex> lk(mut); // 資料準備好後,使用lock_guard來鎖定訊號量,將資料插入佇列之中 data_queue.push(data); std::cout << "data_preparation_thread notify_one" << std::endl; // 通過條件變數通知其它等待的執行緒 data_cond.notify_one(); } } void data_processing_thread() { while(true) { std::cout << "data_processing_thread while" << std::endl; // 使用unique_lock,因為我們需要在取得資料之後,處理資料之間,解鎖mutex std::unique_lock<std::mutex> lk(mut); std::cout << "data_processing_thread before wait" << std::endl; // 等待條件滿足,unique_lock和Lambda函式,判斷資料佇列是否為空 data_cond.wait(lk,[]{return !data_queue.empty();}); std::cout << "data_processing_thread pass wait" << std::endl; data_chunk data=data_queue.front(); data_queue.pop(); // 處理資料需要較多時間,所以先解鎖mutex lk.unlock(); std::cout << "data_processing_thread process data" << std::endl; process(data); if(is_last_chunk(data)) break; } } int main() { std::cout << "main" << std::endl; std::thread t1(data_preparation_thread); std::thread t2(data_processing_thread); t1.join(); t2.join(); }
main
data_preparation_thread while
data_preparation_thread prepare_data
data_processing_thread while
data_processing_thread before wait
a
data_preparation_thread notify_one
data_preparation_thread while
data_preparation_thread prepare_data
data_processing_thread pass wait
data_processing_thread process data
process data: a
data_processing_thread while
data_processing_thread before wait
q
data_preparation_thread notify_one
data_processing_thread pass wait
data_processing_thread process data
process data: q
--------------------------------
Process exited after 4.063 seconds with return value 0
Press any key to continue . . .
相關推薦
[C++11 併發程式設計] 11
上一節,我們瞭解瞭如何對執行緒之間的共享資源進行保護的方法。但是,有些時候,我們需要線上程之間進行同步操作。一個執行緒等待另一個執行緒完成某項工作後,再繼續自己的工作。比如,某個執行緒需要等待一個訊息,或者某個條件變成true。接下來幾節,我們會看到如何使用C++標準庫來做
C++11併發程式設計:原子操作atomic
一:概述 專案中經常用遇到多執行緒操作共享資料問題,常用的處理方式是對共享資料進行加鎖,如果多執行緒操作共享變數也同樣採用這種方式。 為什麼要對共享變數加鎖或使用原子操作?如兩個執行緒操作同一變數過程中,一個執行緒執行過程中可能被核心臨時掛起,這就是執行緒切換,當核心再次切換到該執行緒時,之前的資
C++11 併發程式設計指南——前言
開場白:前一段時間(大概在8月初)開始寫 《C++11 併發程式設計指南》(最早更新於:http://www.cnblogs.com/haippy),但是由於個人能力有限,加上 9 月初到現在一直在忙著找工作(革命尚未成功),精力有限,難免出現錯誤,希望讀者不吝指正。 另外,這是我在併發程式設
[C++11 併發程式設計] 07
假設有兩個執行緒,在執行某些操作時,都需要鎖定一對mutex,執行緒A鎖定了mutex A,而執行緒B鎖定了額mutex B,它們都在等待對方釋放另一個mutex,這就會導致這兩個執行緒都無法繼續執行。這種情況就是死鎖。 避免死鎖最簡單的方法是總是以相同的順序對兩個mute
C++11 併發程式設計基礎(一):併發、並行與C++多執行緒
正文 C++11標準在標準庫中為多執行緒提供了元件,這意味著使用C++編寫與平臺無關的多執行緒程式成為可能,而C++程式的可移植性也得到了有力的保證。另外,併發程式設計可提高應用的效能,這對對效能錙銖必較的C++程式設計師來說是值得關注的。 回到頂部 1. 何為併發 併發指的是兩個或多個獨立的活動在同
C++11 併發程式設計教程&學習筆記
C++11 併發程式設計教程&學習筆記 為了能夠編譯本文的示例程式碼,你需要有一個支援 C++11 的編譯器,筆者使用的是 TDM-GCC4.9.2 C++11 併發程式設計教程 - Part 1 : thread 初探
C++11併發程式設計(一)——初始C++11多執行緒庫
1 前言 C++11標準在標準庫中為多執行緒提供了元件,這意味著使用C++編寫與平臺無關的多執行緒程式成為可能,而C++程式的可移植性也得到了有力的保證。 在之前我們主要使用的多執行緒庫要麼
[C++11 併發程式設計] 17 超時等待
之前我們看到的所有等待機制都是不會超時的,也就是說,等待某個同步事件的執行緒會一直掛起。有些情況下,我們希望設定一個最長等待時間,使得程式可以繼續與使用者進行互動,使得使用者可以取消這個操作。我們先來看看C++11提供的時鐘類clock: clock clock提供瞭如下四
[C++11 併發程式設計] 15 承諾promise
假設有一個應用程式應用程式用於處理大量的網路連線,通常我們會為每一個連線建立單獨的處理執行緒。當執行緒數量較少時,這樣是可行的,但是隨著連線數量的增加,大量的執行緒需要消耗大量的系統資源。這樣,使用較少的執行緒,每個執行緒處理多個連線更為合適。 std::promise&l
[C++11 併發程式設計] 04
C++標準模板庫提供了一個輔助函式 - std::thread::hardware_concurrency(),通過這個函式,我們可以獲取應用程式可以真正併發執行的執行緒數量。下面這個例子,實現了一個併發版本的std::accumulate,它將工作拆分到多個執行緒中,為了
Java併發程式設計(11)-條件變數Condition的使用
文章目錄 一、併發程式設計中的條件變數 1.1、從生產者-消費者模型理解條件變數 1.2、Condition介面 1.3、Condition介面方法 二、實現一個生產者-消費
多執行緒高併發程式設計(11) -- 非阻塞演算法實現ConcurrentLinkedQueue原始碼分析
一.背景 要實現對佇列的安全訪問,有兩種方式:阻塞演算法和非阻塞演算法。阻塞演算法的實現是使用一把鎖(出隊和入隊同一把鎖ArrayBlockingQueue)和兩把鎖(出隊和入隊各一把鎖LinkedBlockingQueue)來實現;非阻塞演算法使用自旋+CAS實現。 今天來探究下使用非阻塞演算法
併發程式設計(三): 使用C++11實現無鎖stack(lock-free stack)
C++11中CAS實現: template< class T> struct atomic { public: bool compare_exchange_weak( T& expected, T desired,
C++併發程式設計(C++11)
前言 首先需要說明,本部落格的主要內容參考自Forhappy && Haippy博主的分享,本人主要是參照博主的資料進行了學習和總結,並適當的衍生或補充了相關的其他知識內容。 C++11有了std::thread 以後,可以在語言層面編寫多執
c++併發程式設計實戰(C++11)pdf 高清
C++併發程式設計實戰PDF高清完整版下載。C++併發程式設計實戰PDF是一本非常熱門的電子圖書。這本書籍是由由威廉姆斯所著的,裡面擁有非常詳細的講解,對於新手來說是本不錯的書。 下載地址:http://download.csdn.net/download/l
C++11併發/多執行緒程式設計系列(2)
std::thread詳解 std::thread在標頭檔案<thread>中宣告,因此使用 std::thread 時需要包含 <thread>標頭檔案。 default(1) thread() noexcept;
併發程式設計-完美單例模式 時間:2018/11/1
class God { private static God instance = null; private static object locker = new object(); private God(){} //建構函式私有 public static Go
C++11 thread程式設計呼叫類方法並傳入引數
#include <thread> #include <iostream> class classA { public : classA() { std::cout<<" classA " <<std::endl; }
C++11併發學習之三:執行緒同步
1.<mutex> 標頭檔案介紹 (1)Mutex系列類(四種) std::mutex,最基本的 Mutex 類。 std::recursive_mutex,遞迴 Mutex 類。 std::time_mutex,定時 Mutex 類。 std::recursive_ti
C++11併發學習之一:小試牛刀
1.與C++11多執行緒相關的標頭檔案 C++11 新標準中引入了四個標頭檔案來支援多執行緒程式設計,他們分別是<atomic> ,<thread>,<mutex>,<condition_variable>和<future>。 <at