std::thread執行緒詳解
目錄
簡介
本文主要介紹了標準庫中的執行緒部分。執行緒是目前多核程式設計裡面最重要的一部分。
與程序程序相比,其所需的資源更少,執行緒之間溝通的方法更多; 他們之間的區別可以比較簡明用以下幾點概括[1]:
- 程序是資源分配的最小單位,執行緒是CPU排程的最小單位;也就是說程序之間的資源是相互隔離,而執行緒之間的是可以相互訪問的。
- 執行緒的存在依賴於程序,一個程序可以保護多個執行緒;
- 程序出現錯誤不會影響其他程序,但是一個執行緒出現錯誤,會影響同一程序下的所有執行緒。
執行緒的使用
執行緒的建立
一般使用std::thread
建立一個執行緒。std::thread
支援輸入一個函式物件,及一些引數,類似於std::bind
,不過沒有佔位符。
最常見,最簡單的是對輸入一個匿名函式作為引數:
1
2
3
4
std::thread t1([]() {
std::cout << "Hello World" << std::endl;
});
t1.join();
需要注意的是,在使用多執行緒的時候,如果使用類似於std::cout << "Hello World" << std::endl;
的語句,容易造成輸出的混亂。比如
1
2
3
4
5
6
7
8
std::thread t1([]() {
std::cout << "Hello World1" << std::endl;
});
std::thread t2([]() {
std::cout << "Hello World2" << std::endl;
});
t1.join();
t2.join();
以上程式碼,我們一般來說期望的輸出是
但是,在一些情況下,它還會以以下的方法輸出
造成這個的原因很簡單,因為"Hello World"
和std::endl
的輸出是分開的,所以他們之間可能被插入其他的輸出。為了解決這個問題。一般會使用一個完整的字串進行輸出,但是C++在格式化這一方面做的比較差(C++20
format
庫看起來還不錯),所以一般情況下會使用printf
輸出。
執行緒的方法和屬性
-
joinable()
判斷執行緒是否可連線(可執行執行緒)的,有以下情況的,為不可連線的:- 構造時,
thread()
沒有引數; - 該物件的執行緒已經被移動了;
- 該執行緒已經被
join
或detach
;
- 構造時,
-
get_id()
返回執行緒的ID; -
native_handle()
返回POSIX
標準的執行緒物件; -
join()
等待執行緒執行完成; -
detach()
分離執行緒,分離後物件不再擁有執行緒。該執行緒結束後,會自動回收記憶體。(並不會開啟另一個程序); -
swap()
交換物件的執行緒。
std::jthread (C++20)
除了常用的std::thread
外,標準庫還存在著另一個可以建立執行緒的類,std::jthread
。他們之間的差別比較明顯的就是,std::jthread
會在解構的時候判斷執行緒是否還在執行joinable
,如果還在執行則自動呼叫request_stop
和join
。
除此之外,std::jthread
還提供了一個內建的std::stop_token
。可以通過執行緒函式的第一個引數來獲取(如果函式的第一個引數型別為std::stop_token
)。
可以通過get_stop_source
、get_stop_token
、request_stop
等方法來對其進行操作。
stop_token (C++20)
stop_token
類似於一個訊號,告訴執行緒是否到了結束的時候。和stop_source
一起使用。stop_token
用來獲取是否退出(讀),而stop_source
用來請求推出(讀寫)。其方法:
-
request_stop
請求退出 -
stop_requested
獲取是否已經請求退出 -
stop_possible
獲取是否可以請求退出
樣例:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
void thread_func(std::stop_token token) {
int data = 0;
while (!token.stop_requested()) {
printf("%d\n", data);
data++;
std::this_thread::sleep_for(1s);
}
printf("Exit\n");
}
int main() {
std::jthread mythread(thread_func);
std::this_thread::sleep_for(4s);
return 0;
}
輸出:
總結
本次講述了執行緒建立的一些方法,可以看到相比較C語言而言,由於C++11提出的函式物件(普通函式、匿名函式,std::bind
的輸出等)使得執行緒的建立更加的方便。
下一次將講述執行緒之間的通訊。在C++中,執行緒之間的通訊方法和C語言提供的類似,不過是將其包裝了一下。