C11 多线程初学1
C++ 11 多線程編程
- 1、線程的創建和使用
- 1.1 創建線程
- 1.2 線程的使用
- 2.實現線程同步
- 2.1互斥鎖
- 2.2 條件變量
- 3.例
- 1:兩線程交替打印奇偶數
1、線程的創建和使用
引入線程庫<thread>,其提供了thread類,創建一個線程即實例化一個該類的對象,以此進行線程的創建和使用。
#include<thread> using namespce std;1.1 創建線程
一個線程可以用一個 thread 類的對象來表示,thread類中重載了構造函數和移動拷貝構造
#include<iostream> #include<thread>using namespace std;void funa() {cout << "thread_funa()" << endl; } int main() {//創建線程——構造函數thread a(funa);cout << a.get_id() << endl;//移動拷貝構造thread b(std::move(a));cout << b.get_id() << endl;b.join();//移動拷貝構造進行資源的交換,所有要注釋掉//a.join();cout << "main end" << endl;}注意: thread類無拷貝構造函數、無賦值運算符,即不能直接用一個事先定義好的thread對象拷貝構造另一個thread對象,也不能不能進行賦值操作。但可以將臨時的thread對象賦值給另一個thread即移動拷貝構造,也可以移動賦值。
1.2 線程的使用
thread 提供的函數: 線程支持庫
thread類常用的成員函數:
| get_id() | 獲取當前thread對象的線程id |
| joinable() | 判斷當前線程是否活躍(是:true;否:false)即是否支持調用 join() |
| join() | 阻塞當前thread 對象所在的線程,直至thread 對象表示的線程執行完畢 |
| detach() | 將當前線程從調用該函數的線程中分離出去,他們彼此獨立運行 |
| swap() | 交換兩個線程的狀態 |
注意:每個thread 對象在調用析構銷毀前,要么調用 join() 函數令主線程等待子線程執行完畢,要么調用detach() 函數將子線程和主線程分離,二者必選一,否則存在以下問題:
- 線程占用的資源無法全部釋放,造成內存泄露
- 當主線程執行完畢而子線程未完時,程序執行引發異常。
在this_thread 命名空間的部分函數:
| get_id() | 獲得當前線程的 ID |
| yield() | 阻塞當前線程讓出cpu,直至條件成熟 |
| sleep_for() | 阻塞當前線程指定的時間 |
| sleep_until() | 阻塞當前線程,直至某個時間點為止 |
例:
//休眠1000毫秒,1s this_thread::sleep_for(chrono::milliseconds(1000));2.實現線程同步
2.1互斥鎖
互斥鎖用 mutex 類(位于std命名空間中)的對象表示,定義在頭文件<mutex>頭文件中。
成員函數:lock()——加鎖; unlock()——解鎖
例:對臨界資源變量n的訪問
實現嚴格基于作用域的互斥體所有權包裝器:lock_fuard
原理:創建 lock_guard 對象時,它試圖接收給定互斥的所有權。控制離開創建 lock_guard 對象的作用域時,銷毀 lock_guard 并釋放互斥。即,創建即加鎖,作用域結束自動解鎖。
lock_gurad傳入兩個參數,第二個為adopt_lock標識時,表示該互斥量之前必須已經lock,才能使用此參數,故需要提前手動鎖定。
#include<mutex> using namespcase std; mutex m; //實例化mutex對象m void Show_n() {m.lock(); //手動鎖定lock_guard<mutex> g1(m, adopt_lock);cout << n << endl; } //作用域結束,析構g1,m解鎖實現可移動的互斥體所有權包裝器:unique_lock
與lock_guard類似,用法更豐富。
| lock() | 鎖定 |
| try_lock() | 嘗試鎖定,若不能,先去執行其他代碼并返回false;可以,進行加鎖并返回true |
| unlock() | 解鎖 |
unique_lock與lock_guard
| 手動lock、unlock | 支持 | 不支持 |
| 參數 | 支持 adopt_lock/try_to_lock/defer_lock | 支持 adopt_lock |
try_to_lock: 嘗試用mutx的lock()去鎖定這個mutex,但如果沒有鎖定成功,會立即返回,不會阻塞在那里
defer_lock: 這個參數表示暫時先不lock,之后手動去lock,但是使用之前也是不允許去lock。
2.2 條件變量
C11提供的兩種表示條件變量的類:
都定義在<condition_variable>頭文件中,常與互斥鎖搭配使用,避免線程間搶奪資源。
- condition_variable
該類表示的條件變量只能和unique_lock類表示的互斥鎖搭配使用; - condition_variable_any
該類表示的條件變量可以與任意類型的互斥鎖搭配使用(如:遞歸互斥鎖、定時互斥鎖等)
條件變量常用的成員函數
| wait() | 阻塞當前線程,等待條件成立 |
| wait_for() | 阻塞當前線程的過程中,該函數會自動調用unlock()解鎖,令其他線程使用公共資源。當條件成立或超過指定的等待時間,該函數自動調用lock()加鎖,同時令線程繼續執行 |
| wait_until() | 與wait_for() 類似,區別是其可以設定一個具體的時間點,當條件成立或等待時間超過了指定的時間點,函數自動加鎖,線程執行 |
| notify_one() | 喚醒一個等待的線程 |
| notify_all() | 喚醒所有等待線程 |
關于wait() :
調用wait()1先獲得mutex,2線程被阻塞,當wait陷入休眠是會自動釋放mutex。直到另外某個線程調用 notify_one或notify_all喚醒了當前線程。當線程被喚醒時,此時線程是已經自動占有了mutex。
3.例
1:兩線程交替打印奇偶數
#include<iostream> #include<thread> #include<mutex> using namespace std; std::mutex data_mutex; std::condition_variable data_var; bool tag = true; // odd : 1 // even: 2 // odd : 3 // even : 4void printodd() // 打印奇數 {std::unique_lock<std::mutex> ulock(data_mutex);for (int odd = 1; odd <= 100; odd += 2){while (!tag){data_var.wait(ulock);}cout << "odd: " << odd << endl;tag = false;data_var.notify_all();} } void printeven() //打印偶數 {std::unique_lock<std::mutex> ulock(data_mutex);for (int even = 2; even <= 100; even += 2){ while (tag){data_var.wait(ulock);// 1 2 }cout << "even: " << even << endl;tag = true;data_var.notify_all();} }int main() {thread thodd(printodd);thread theven(printeven);thodd.join();theven.join();return 0; }參考文獻:
C++多線程unique_lock詳解
總結
以上是生活随笔為你收集整理的C11 多线程初学1的全部內容,希望文章能夠幫你解決所遇到的問題。
- 上一篇: net core体系-web应用程序-4
- 下一篇: HDU 4383 To The Moon