C++11 多線程

新特性之描述:
雖然 C++11 會在語言的定義上提供一個內存模型以支持線程,但線程的使用主要將以 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 此一提案因此而受到了批評。

更高級的線程支持,如線程池,已經決定留待在未來的 Technical Report 加入此類支持。更高級的線程支持不會是 C++11 的一部份,但設想是其最終實現將創建在目前已有的線程支持之上。
std::async 提供了一個簡便方法以用來運行線程,並將線程綁定在 std::future。用戶可以選擇一個工作是要多個線程上異步的運行,或是在一個線程上運行並等待其所需要的數據。默認的情況,實現可以根據底層硬件選擇前面兩個選項的其中之一。另外在較簡單的使用情形下,實現也可以利用線程池提供支持。

具體細節:

C++標準線程庫簡潔且強大,跨平臺顯得毫無壓力可言。這麼好用的東西,爲什麼不趕快試試呢?

要使用標準線程庫需要包括頭文件
#include <thread>
#include <mutex>
#include <condition_variable>

這三個頭文件涵蓋了新標準的大部分內容,完全可以滿足項目的需求,C++線程庫源自boost,大部分內容都非常接近。

//非常簡單不是麼?
void run()
{
std::cout<<"Hello C++ Thread!"<<std::endl;

std::chrono::duration<int> a(5);// 睡眠持續5秒
std::this_thread::sleep_for(a);

std::cout<<"waked up"<<std::endl;
}

int _tmain(int argc, _TCHAR* argv[])
{

std::thread t(run);// 初始化新的線程,run爲傳遞的回調函數

t.join(); // 阻塞主線程,直到線程t完成所有操作

return 0;
}

極具魅力與誘惑的存在,封裝的實在是太好了,使用起來非常的簡潔方便。

多線程不可避免的需要談到互斥鎖,C++新標準自帶了4種互斥鎖,實現方法大同小異,下面趕快來看看。

std::mutex iomutex;
std::recursive_mutex;
std::timed_mutex tmutex;
std::recursive_timed_mutex;

具體實現:
std::mutex iomutex;

void run()
{
iomutex.lock();// 當全局互斥鎖iomutex被鎖定時,其它請求線程進入阻塞隊列等待

std::cout<<"Hello C++ Thread!"<<std::endl;

std::chrono::milliseconds a(5000);// 睡眠持續5秒
std::this_thread::sleep_for(a);

std::cout<<"waked up"<<std::endl;

iomutex.unlock();
}

int _tmain(int argc, _TCHAR* argv[])
{

std::thread t1(run);// 初始化新的線程,run爲傳遞的回調函數
std::thread t2(run);

t1.join(); // 阻塞主線程,直到線程t完成所有操作
t2.join();

return 0;
}

再來說下遞歸鎖std::recursive_mutex,遞歸鎖的用途只是因爲在臨界區內部的函數中也有鎖的操作,因爲項目模塊分工,你不知道你的隊友是不是也使用相同的互斥鎖,如果這種情況發生的話,悲劇當然就是死鎖啦!不過引入遞歸鎖,這個問題就引刃而解了,不過麻煩的是鎖與解鎖需要匹配,這個是一定要注意的。

超時鎖std::timed_mutex tmutex的用途是爲了搶佔,因爲當一個線程進行臨界區操作的時候,你不知道它在做什麼?如果時間花費非常長呢?超時鎖可以在指定時間內搶佔資源。

std::chrono::duration<int> a(5);
tmutex.try_lock_for(a); //超時時間設爲5秒

// 臨界區

tmutex.unlock();

最後說一下條件變量condition_variable,作用是爲了線程之間的通信操作,比如A線程需要等待B線程完成某項操作纔會繼續執行,這時候A線程需要等待B線程的通知。
這時候使用條件變量來處理,是最不好不過的了。

std::mutex cmutex;
std::condition_variable con_var;

void run1()
{
std::unique_lock<std::mutex> locker(cmutext);
con_var.wait(locker);
}

void run2()
{
if(某項條件成立)
{
con_var.notify_all();//通知所有等待線程恢復執行
}
}
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章