C++11 线程库(高层接口)

来源:互联网 发布:北航软件学院毕业生 编辑:程序博客网 时间:2024/04/30 08:29

如今的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
}

接下来是学习底层的线程接口。以后在写了,今天太晚了!!!~_~!


0 0
原创粉丝点击