C++11 線程庫(高層接口)

如今的CPU是朝着多核發展,在移動端的表現也是如此,4核甚至是8核CPU的手機都出來了。所以線程的作用就能充分利用多核的優勢,充分發掘手機的性能。

C++11也順應時代的潮流,在STL庫中增加了線程庫。但使用線程也會帶來一些問題。那就是不太好調試,而且利用的不好會帶來Data reaces和Dead lock的問題。可能程序的運行與你的設想程序的運行不同。

但畢竟好處還是大於壞處,線程能在很大程度上帶來更好的用戶體驗。使你的主界面不會因爲後臺需要大量的計算或者一些費時的IO操作而卡死。

在C+11中,有兩種使用線程的方法。分別叫做高層的接口和底層的接口。首先看一下高層的接口:

高層的接口是使用future,首先頭文件必須包含<future>,在裏面提供的接口有:



在聲明線程的時候是使用這種方式的:future<返回值> temp(async(...,函數名))這樣就聲明瞭一個線程變量,線程的啓動的話是依靠函數async,但async的啓動線程的行爲時高度複雜的並且依賴於async的第一個參數。

async第一個參數有兩種,

1 lanch::async,他會強制線程立即啓動,如果不能啓動,則會拋出system_error的異常

2 lanch::deferred,這個參數並不會啓動線程,他會一直等到調用wait()或者是get()的時候才啓動線程,如果不調用這兩個成員函數,則線程一直不會啓動

如果需要向函數傳參數的話,則形式爲 future<返回值> temp(async(...,函數名,參數)),也可使用拉姆表達式(ar不太懂這個,以後學習一下)auto f1 = async([]{ 函數名();});

在使用future的時候會有個限制,就是調用get的時候一個線程只能調用一次,否則行爲是未定義的。但有時候需要多次處理併發運算的結果,此時就需要多次調用get。爲了解決這個問題,C++11標準庫提供了,shared_future類,

來處理這種需求。shared_future的用法如下:

shared_future<返回值> temp(async((..,..,));

shared_future的返回值爲:

const T& shared_future<T>::get();

T& shared_future<T>::get();

void shared_future<void>::get();

也可以把shared_future<>傳引用傳給線程:

void doSomeThing(char c , const shared_future<int>&f);

auto f = async(launch::async,doSomeThing,'.',std::ref(f));

根據C++11自修手冊上說的,“相比與使用多個shared_future對象去處理多個get的時候,你可能使用一個共同的shared_future對象去處理,但這樣做會更加危險。”這句話不太理解,以後回來在看看。

在自修手冊上還說明了一個東西,就是在使用線程的時候儘量使用局部變量,即應該採用傳值的方式傳參數,如果拷貝對象的花費太大的時候,應該採用const 引用,保證線程使用的就是單獨的局部變量。

上傳一下自己的試驗性代碼:

#include "stdafx.h"
#include "HighLevel.h"

#include <future>

#include <chrono>


#define SHARE_FUTURE_THREAD
using namespace std;

HighLevel::HighLevel()
{
}


HighLevel::~HighLevel()
{
}


int HighLevel::dosomeThing(char c)
{
std::default_random_engine dre(c);
std::uniform_int_distribution<int> id(10,1000);


for ( int i = 0; i < 10; i++)
{
std::this_thread::sleep_for(std::chrono::microseconds(id(dre)));
std::cout.put(c).flush();
}
return 1;
}


int HighLevel::func1()
{
return dosomeThing('.');
}


int HighLevel::func2()
{
return dosomeThing('+');
}


void HighLevel::func3()
{
std::this_thread::sleep_for(std::chrono::seconds(2));
std::cout<<"func3"<<std::endl;
}


void HighLevel::passArgu(int i)
{
cout<<"i is"<<i<<endl;
}


int HighLevel::qureNum()
{
cout<<"read num";
int num;
cin>>num;


if ( !cin)
{
throw runtime_error("no num error");
}
return num;
}


void HighLevel::shareDosomeThing(char c,shared_future<int> f)
{
try
{
int num = f.get();
for (int i = 0; i < num; i++)
{
this_thread::sleep_for(chrono::microseconds(1000));
cout.put(c).flush();
}
}
catch (const exception& e)
{
cout<<"exception is "<<this_thread::get_id()<<":"<<e.what()<<endl;
}
}
//外部調用的方法
void HighLevel::log()
{
#if def FUTURE_THREAD
//傳參給線程,注意的是要用傳值的方法,如果賦值的代價太大的情況,使用const reference的方法傳參,保證在線程
//裏面使用的是局部變量或者是不改變值
auto tempfunc4 = std::bind(&HighLevel::passArgu,this,1);
std::future<void> result4(std::async(tempfunc4));
//啓動線程的方法
auto tempfunc3 = std::bind(&HighLevel::func3,this);
std::future<void> result3(std::async(tempfunc3));
//假設使用了便會阻塞,知道func3執行完成了
//result3.wait();
auto waitResult = result3.wait_for(chrono::seconds(4));


if ( waitResult == future_status::deferred )
{
cout<<"deferred"<<endl;
}
else if( waitResult == future_status::timeout )
{
cout<<"timeout"<<endl;
}
else if ( waitResult == future_status::ready )
{
cout<<"finish"<<endl;
}


auto temp = std::bind(&HighLevel::func1,this);
std::future<int> result1(std::async(std::launch::async,temp)); //強制線程立即啓動,否則拋出std:system_error的異常
int result2 = func2();
//get的方法只能使用一次,如果使用了多次的話會導致運行的結果是未定義的,使用sharefuture可以使用多次get
int reslut = result1.get() + func2();
std::cout<<"result is "<<reslut<<std::endl;
#elif defined(SHARE_FUTURE_THREAD)
try{
//使用sharefuture可以多次調用get
auto qury = bind(&HighLevel::qureNum,this);
shared_future<int> f = async(qury);

auto dothing = bind(&HighLevel::shareDosomeThing,this,'.',f);
auto f0 = async(launch::async,dothing);
auto dothing1 = bind(&HighLevel::shareDosomeThing,this,'+',f);
auto f1 = async(launch::async,dothing1);
auto dothing2 =  bind(&HighLevel::shareDosomeThing,this,'@',f);
auto f2 = async(launch::async,dothing2);


f0.get();
f1.get();
f2.get();
}catch(const exception& e){
cout<<"exception "<<e.what()<<endl;
}
#endif
}

接下來是學習底層的線程接口。以後在寫了,今天太晚了!!!~_~!


發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章