網(wǎng)站建設客戶需求表 文庫北京網(wǎng)站推廣營銷服務電話
多線程編程使我們的程序能夠同時執(zhí)行多項任務。
在C++11以前,C++沒有標準的多線程庫,只能使用C語言中的pthread,在C++11之后,C++標準庫中增加了thread類用于多線程編程。thread類其實是對pthread的封裝,不過更加好用,現(xiàn)在已經(jīng)廣泛用于C++多線程編程。
C++11的多線程庫主要包含<thread> <mutex> <atomic> <condition_variable> <future>等頭文件,這篇文章只要整理記錄<thread>頭文件的內(nèi)容。
<thread>頭文件中主要就是定義了thread類,thread主要的public接口有以下幾個:
1. 構造函數(shù)---創(chuàng)建線程
thread類提供了默認構造函數(shù),移動構造函數(shù)和一般構造函數(shù),并且禁止編譯器生成拷貝構造函數(shù),以及重載 = 操作符,這倆是不允許的。
三種構造函數(shù)的原型:
//默認構造
thread() noexcept = default;
//移動構造
thread(thread&& __t) noexcept;
//一般構造
template<typename _Callable, typename... _Args>
explicit thread(_Callable&& __f, _Args&&... __args);
最常用的是一般構造函數(shù),使用一般構造函數(shù)創(chuàng)建線程,需要傳入一個入口函數(shù),和這個函數(shù)需要的參數(shù),說白了就是告訴被創(chuàng)建的線程要去做什么事情,如果這個線程有形參,需要跟在后邊一起傳入。
#include <unistd.h>
#include <thread>void fun(int num) {while (num--){sleep(1);std::cout << "thread th " << num << std::endl;}
}int main() {std::thread th(fun, 3);if (th.joinable()){th.join();}}
上邊的例子中std::thread th(fun, 3);創(chuàng)建了一個線程,線程的入口函數(shù)就是void fun(int num)這個函數(shù),開啟線程的時候,同時需要把fun需要的參數(shù)傳進去。
2. get_id
每個線程都有一個唯一的標識符,即線程id,使用get_id函數(shù)可以獲取線程的id;
get_id返回一個類型為std::thread::id
的對象,這是一個類,它對<<運算符進行了重載,所以可以直接用std::cout打印出來。
#include <unistd.h>
#include <thread>void fun(int num) {while (num--){
// sleep(1);
// std::cout << "thread th " << num << std::endl;}
}
int main() {std::thread th(fun, 3);std::cout << th.get_id() << std::endl;std::cout << this_thread::get_id() << std::endl;if (th.joinable()){th.join();}
}
?this_thread是一個命名空間,表示當前線程,當前線程就是main函數(shù)所在的主線程,所以thread::get_id()在這里就是主線程的id。
3. join & detach
void join();
void detach();
第一個例子中,線程開啟之后,有這樣一段代碼
if (th.joinable())
{th.join();
}
這段代碼意思是等待th線程執(zhí)行完畢,主線程再繼續(xù)往下執(zhí)行。
如果把這段代碼注釋掉,會得到這樣的結果
這是因為th線程尚未執(zhí)行完畢,主線程就退出了,所以th線程被強行中斷了,而且終端會打印一段錯誤信息(terminate called without an active exception) 。
join 和 detach 是線程兩種不同的運行方式:
- join表示等待,調(diào)用后會阻塞當前線程,直到join線程執(zhí)行完畢,調(diào)用者才繼續(xù)往下執(zhí)行;
- detach表示分離,程序不會等待detach線程執(zhí)行完,且程序退出之后,detach線程由系統(tǒng)接管繼續(xù)執(zhí)行。
4. joinable
bool joinable() const noexcept;
在調(diào)用join或者detach之前,先判斷線程是否joinable,是一個良好的習慣。
從一般構造函數(shù)創(chuàng)建的線程,他們的joinable都是ture,可以進行join或者detach,而且,對線程進行join和detah是必要的,這樣可以明確告訴程序,該怎么調(diào)度這個線程,避免不必要的錯誤發(fā)生。
具體原因可以看這里。
5. 析構函數(shù)
~thread()
{if (joinable()){std::terminate();}}
從析構函數(shù)可以看出來,如果一個線程在釋放的時候還是joinable的,那么整個程序都會退出,這也是為什么線程一定要調(diào)用join或者detach的原因,調(diào)用了join和detach之后,線程的joinable就為false了。
上邊說到join和detach的時候,嘗試把join刪掉了,確實會導致程序報錯。
6. swap
void swap (thread& x) noexcept;
交換兩個線程的所有屬性。