一 C++11多線程簡介
C++11標準庫會提供類thread
(std::thread
)。若要運行一個線程,可以創建一個類thread
的實體,其初始參數爲一個函數對象,以及該函數對象所需要的參數。通過成員函數std::thread::join()
對線程會合的支持,一個線程可以暫停直到其它線程運行完畢。若有底層平臺支持,成員函數std::thread::native_handle()
將可提供對原生線程對象運行平臺特定的操作。對於線程間的同步,標準庫將會提供適當的互斥鎖(像是std::mutex
,std::recursive_mutex
等等)和條件參數(std::condition_variable
和std::condition_variable_any
)。前述同步機制將會以RAII鎖(std::lock_guard
和std::unique_lock
)和鎖相關算法的方式呈現,以方便程序員使用。
對於要求高性能,或是極底層的工作,有時或甚至是必須的,我們希望線程間的通信能避免互斥鎖使用上的開銷。以原子操作來訪問內存可以達成此目的。針對不同情況,我們可以通過顯性的內存屏障改變該訪問內存動作的可見性。
對於線程間異步的傳輸,C++11標準庫加入了以及std::packaged_task
用來包裝一個會傳回異步結果的函數調用。因爲缺少結合數個future的功能,和無法判定一組promise集合中的某一個promise是否完成,futures此一提案因此而受到了批評。
更高級的線程支持,如線程池,已經決定留待在未來的TechnicalReport加入此類支持。更高級的線程支持不會是C++11的一部分,但設想是其最終實現將創建在目前已有的線程支持之上。
std::async
提供了一個簡便方法以用來運行線程,並將線程綁定在std::future
。用戶可以選擇一個工作是要多個線程上異步的運行,或是在一個線程上運行並等待其所需要的數據。默認的情況,實現可以根據底層硬件選擇前面兩個選項的其中之一。另外在較簡單的使用情形下,實現也可以利用線程池提供支持。
二 簡單std::thread的使用
#include <iostream>
#include <thread>
using namespace std;
void myFirstThread()
{
cout << "Hello thread" << endl;
}
int main()
{
thread myThread(myFirstThread);
myThread.join();
return 0;
}
三 std::thread類構造函數函數簡介
std::thread構造
1 默認構造,創建一個空的thread對象,以下爲默認構造函數聲明:
thread() noexcept;
2拷貝構造 copy-delete(thread對象不可拷貝構造):
thread (const thread&) = delete;
3初始化構造,創建thread對象,該對象可被joinable,線程會調用fn函數,參數由args給出,下邊爲初始化構造 函數聲明:
template <class Fn, class... Args>
explicit thread (Fn&& fn,Args&&... args);
4移動構造 move,此構造函數調用成功之後,x不代表任何thread可執行對象。
thread (thread&& x) noexcept;
注意:可被joinable的thread對象必須在他們銷燬之前被主線程join或者將之設置爲detached。
std::thread各種構造函數示例如下:
#include <iostream>
#include <thread>
using namespace std;
void myFirstThreadTask(int num)
{
for (int i = 0; i < 10; ++i)
{
cout << "myFirstThreadTask's num = " << num++ << endl;
this_thread::sleep_for(chrono::milliseconds(10));
}
}
void mySecondThreadTask(int &num)
{
for (int i = 0; i < 10; ++i)
{
cout << "mySecondThreadTask's num = " << num++ << endl;
this_thread::sleep_for(std::chrono::milliseconds(10));
}
}
int main(int argc, _TCHAR* argv[])
{
int n = 5;
thread myThread0;//myThread1爲一個空線程,不代表任何可執行對象
//myThread1與myFirstThreadTask函數綁定,n爲其按值傳遞參數
thread myThread1(myFirstThreadTask,n);
//myThread2與mySecondThreadTask函數綁定,n爲其引用傳遞參數
thread myThread2(mySecondThreadTask,std::ref(n));
//現在myThread2不代表任何可執行對象,myThread3與mySecondThreadTask函數綁定
thread myThread3(std::move(myThread2));
myThread1.join();
myThread3.join();
//myThread3.join();
return 0;
}