建立執行緒的四種方法:
執行緒類的建構函式是變參建構函式,第乙個引數是執行緒函式,後面的引數為執行緒函式的引數(引數通過值傳遞方式,若要引用傳遞須加std::ref())。
thread t1 (counter, 1, 6); //void counter(int, int);
//class counter 實現 operator()
1) thread t1; //c++統一推薦方法
2) counter c(1, 20);
thread t2(c);
3) thread t3(counter(1,20));
比較第一種和第三種構造方式,如果函式物件的建構函式不需要任何引數。 thread t3(counter());是不行的,因為編譯器會認為你在宣告乙個函式,函式名為t3,此時只能用第一種構造方式。
thread t1 ((int, int), 1, 6);
// class counter c();
thread t;
一般常見的是乙個類自己建立乙個後台處理執行緒:thread t;
執行緒本地儲存 thread_local
thread_local int n;多執行緒程式設計經常需要操作共享的記憶體,在讀/寫過程中會導致競爭條件。
例如:int counter = 0;
++counter; //因為++counter不時原子操作,多個執行緒中出現此操作時不是執行緒安全的。
應該用:
atomiccounter(0); //等效於 atomic_int counter(0);
++counter; //此時多個執行緒執行++counter是乙個原子操作,是執行緒安全的。
例:void func( std::atomic&counter)
intmain()
);
for( auto&t : threads )
t.join();
//呼叫join,如果執行緒未結束,則main函式阻塞於此。
std::count
<<"
result=
"return0;
}/*join的呼叫會導致呼叫執行緒阻塞於此,若不希望呼叫執行緒阻塞,但又想知道被調執行緒是否結束,應當用其它方式,例如訊息...
*/
編寫多執行緒必須分外留意操作順序,如果無法避免執行緒共享資料,則必須提供同步機制,保證一次只有乙個執行緒能更改資料。使用互斥解決競爭條件,可能導致死鎖。
1) 非定時互斥體類std::mutex std::recursive_mutex
lock() : 嘗試獲取鎖,並且阻塞直到獲取鎖。
try_lock() : 嘗試獲取鎖,並立即返回,成功獲取返回true,否則false。
unlock() : 釋放鎖。
mutex與recursive_mutex的區別在於,前者已經獲得所後不得再嘗試獲取,這會死鎖,後者能遞迴獲取,注意釋放次數應與獲取次數相等。
2) 定時互斥鎖類std::timed_mutex std::recursive_timed_mutex
lock() , try_lock() , unlock()
try_lock_for(rel_time) : 指定相對時間內獲得返回true, 超時返回false。
try_lock_until(abs_time) : 指定系統絕對時間內獲得返回true, 超時返回false。
timed_mutex與recursive_timed_mutex區別同上。
鎖類是乙個包裝器,析構函式會自動釋放關聯的互斥體。
1) 簡單鎖std::lock_guard
其建構函式會要求獲得互斥體,並阻塞直到獲得鎖。
2) 複雜鎖std::unique_lock
explict unique_lock( mutex_type& m); //阻塞直到獲得鎖。
unique_lock(mutex_type& m, defer_lock_t) noexcept; //
儲存乙個互斥體引用,不會立即嘗試獲得鎖。鎖可以在以後獲得。
unique_lock(mutex_type& m, try_to_lock_t); //
嘗試獲得引用的互斥鎖,未能獲得也不阻塞。
unique_lock(mutex_type& m, adopt_lock_t); //
該鎖假定執行緒獲得引用的互斥鎖,並負責管理這個鎖。
template
unique_lock(mutex& m, const chrono::time_point& abs_time); //
嘗試獲取該鎖,直到超過給定的絕對時間。
template
unique_lock(mutex& m, const chrono::duration& rel_time); //
嘗試獲取該鎖,直到超過給定的相對時間。
unique_lock類還支援lock(), try_lock(), try_lock_for(), try_lock_until()等方法。
通過owns_lock()檢視是否獲得了這個鎖;也可以用if對unique_lock物件直接判斷是否獲得鎖,因為它定義了bool()運算子。
1) 泛型lock可變引數模板函式
template
void lock(l1&, l2&, l3&...);
按順序鎖定,如果乙個互斥體丟擲異常,會對已獲得的鎖unlock。
2) 泛型try_lock
template
int try_lock(l1&, l2&, l3&...);
通過順序呼叫互斥體物件的try_lock,成功返回-1,失敗返回從0開始的位置索引,並對已獲得的鎖unlock。
引數順序每次應保持一致, 否則易死鎖。
保證call_once排程的函式只被執行一次。
//1. 簡單鎖
mutex mmutex;
lock_guard
mlock(mmutex);
//2. 定時鎖
timed_mutex mtimemutex;
unique_lock
mlock(mtimedmutex, chrono::milliseconds(200
));//
3. 泛型
mutex mut1;
mutex mut2;
unique_lock
lock1(mut1, defer_lock_t());
unique_lock
lock2(mut2, defer_lock_t());
lock
(lock1, lock2);
//4. 雙重檢查鎖定演算法 (代替call_once的用法)
class
myclass
private
:
int *p;
}myclass
var;
bool initialized = false
;mutex mut;
void
func()
}cout
<<"ok"
<兩次檢查initialized。獲得鎖之前和獲得鎖之後,確保init只呼叫一次。
notify_one(); //喚醒等待這個條件變數的執行緒之一
notify_all(); //
喚醒所有等待這個條件變數的執行緒 //
1)前提是已經獲得lk的鎖 //
2)呼叫wait會unlock lk,然後等待 //
3)當被喚醒後 lock lk
wait( unique_lock&lk);
wait_for(unique_lock
& lk, const chrono::duration&rel_time);
wait_until(unique_lock
&lk, const chrono::time_point& abs_time);
//例:向佇列中加入資料,當佇列不為空時,後台執行緒被喚醒處理資料
std::queuestring>mqueue;
std::mutex mmutex;
std::condition_variable mcondvar;
//向佇列加入資料的執行緒
unique_locklock
(mmutex);
mqueue.push( data);
mcondvar.notify_all();
//後台處理資料的執行緒
unique_locklock
(mmutex);
while(true
)
promise/future模型方便獲取執行緒返回的結果、執行緒間通訊、處理異常
C 11 多執行緒
新特性之描述 雖然 c 11 會在語言的定義上提供乙個記憶體模型以支援執行緒,但執行緒的使用主要將以 c 11 標準庫的方式呈現。c 11 標準庫會提供型別 thread std thread 若要執行乙個執行緒,可以建立乙個型別 thread 的實體,其初始引數為乙個函式物件,以及該函式物件所需要...
c 11 多執行緒
1.多執行緒的原理 同一時間內,cpu只能處理1條執行緒,只有1條執行緒在工作 執行 多執行緒併發 同時 執行,其實是cpu快速地在多條執行緒之間排程 切換 如果cpu排程執行緒的時間足夠快,就造成了多執行緒併發執行的假象。思考 如果執行緒非常非常多,會發生什麼情況?cpu會在n多執行緒之間排程,c...
C 11 多執行緒
2011 年 c 迎來重大的改革 語言層面上承認了 多執行緒 程式的存在 加入了 thread 多執行緒支援庫,內容豐富 功能強大。首先從我個人理解角度粗鄙的理解一下多執行緒。多執行緒眾所周知 切割時間片的多程式併發執行,大多數的計算機都支援多執行緒併發的硬體支援。這可能是最簡單的多執行緒程式了。多...