C++ async 函数的使用

future<T>提供了一种异步获得线程中的函数返回值的方法 。future<T>表示一个类型为T的future值,这个值可以通过future<t>的get()函数来获取。这个值在线程开始执行时还是不可用的,是一个“未来的期望值”。get()函数是同步的,从子线程获取时阻塞当前线程,直到返回。

future<>可以被packaged_task<>和promise<>包装。

packaged_task<>包含两个基本的元素A  stored  task(即一个广义的可调用对象)和A  shared  state, 是一个泛化的可调用对象的包装器,类似于function<>,不过不能接受bind() 返回值。package_task<>包装对象得到包装对象,能够通过包装的对象的get_future() 方法返回一个future对象,借由future对象便可以异步得到调用被包装的可调用对象的返回值。

于是,可以将packaged_task<>包装的可调用对象,在另外一个线程来执行,最后通过future<>传出在执行的结果。

 

#include <future>
#include <thread>
#include <chrono>
#include <random>
#include <iostream>

using namespace std;

thread::id doSomething(char c)
{
    // random - number generator(use c as seed to get different sequences)
    default_random_engine dre(c);
    uniform_int_distribution<int> id(10, 1000);
    // loop to print character after a random period oftime
    for (int i = 0; i < 10; ++i)
    {
        this_thread::sleep_for(chrono::milliseconds(id(dre)));
        cout.put(c).flush();
    }
    return this_thread::get_id();
}

int main()
{
    function<thread::id(char)> func(doSomething);
    packaged_task<thread::id(char)> task1(doSomething);    
    packaged_task<thread::id(char)> task2(doSomething);

    future<thread::id> f1 = task1.get_future();
    future<thread::id> f2 = task2.get_future();   //将task2放到子线程中执行 

    //packaged_task::operator() 
    //void operator()(ArgTypes... args);
    task1('@');
    cout << endl;

    //function::operator()
    //result_type operator()(T1 t1, T2 t2, ..., TN tN);
    cout << func('x') << endl;
    
    
    cout << f1.get() << endl;   //异步的来检索结果

    thread t(ref(task2),'a');      //创建线程来执行task2    packaged_task<>不能够被拷贝,只能移动,所以这里只能用ref()  因为reference_wrapper是可拷贝的
                                     //或者move()进行移动拷贝
                                   //packaged_task只有一个默认构造函数和一个移动拷贝构造函数和两个模板构造函数
                                   //ref(x)的返回值是一个右值,这个右值相当于x的引用,ref() 返回的reference_wrapper类实例是可以拷贝和赋值的
    cout << f2.get() << endl;
    t.join();

    cin.get();
    return 0;
}

 


 

promise<>用来方便的获取线程当中的某个值,通过给线程函数传入一个promise<>类型的参数。

 

这里有一个疑问,thread 是个类,其构造函数有如下4种形式:

//default (1)
thread() noexcept;

//initialization(2)
template <class Fn, class... Args>
explicit thread(Fn&& fn, Args&&... args);

//copy[deleted](3)
thread(const thread&) = delete;

//move(4)
thread(thread&& x) noexcept;

1是默认构造函数,构造出的对象不是一个可执行的线程。2是模板形式的带参数的构造函数,3表示拷贝构造不可用,4表示支持移动构造。这样说来,用一个可调用对象,带上绑定的调用时的参数,调用的是2.      可是2中函数的参数是Fn&&形式的,即万能引用,即最终实例化之后,推断的类型要么是左值引用,要么是右值引用。但是种种测试代码表明,thread类如此实例化时,总是值传递而已。需要传引用时,还得用ref() 来包装。

 

类似的还有bind(),   测试代码和各种示范代码表明,是值传递,需要用ref() 包装。在MSDN2013上的DOC上,看到的原型是这样的,

template<class Fty, class T1, class T2, ..., class TN>
unspecified bind(Fty fn, T1 t1, T2 t2, ..., TN tN);

template<class Ret, class Fty, class T1, class T2, ..., class TN>
unspecified bind(Fty fn, T1 t1, T2 t2, ..., TN tN);

和值传递是吻合的。

 

但在cplusplus.com上看到的却是这样的:

//simple(1)	
template <class Fn, class... Args>
  /* unspecified */ bind (Fn&& fn, Args&&... args);

//with return type (2)	
template <class Ret, class Fn, class... Args>
  /* unspecified */ bind (Fn&& fn, Args&&... args);

 

 

显然是应该引用传递的,这是另外一个疑惑的地方。

 

 

 

#include <thread>
#include <future>
#include <iostream>
#include <string>
#include <exception>
#include <stdexcept>
#include <functional>
#include <utility>

using namespace std;

thread::id doSomething(std::promise<std::string>& p)   //传入一个promise作为参数
{
    try {
        //read character and throw exceptiopn if’x’
        std::cout << "read char (’x’ for exception): ";
        char c = std::cin.get();
        if (c == 'x') 
        {
            throw std::runtime_error(std::string("char ") + c + " read");
        }
        std::string s = std::string("char ") + c + " processed";
        p.set_value(std::move(s)); //store result     设置的值最后通过future<>获得
    }
    catch (...) {
        p.set_exception(std::current_exception()); //store exception   设置异常,最后在父线程中捕获
    }
    return this_thread::get_id();
}

int main()
{
    try {
        //start thread using a promise to store the outcome
        std::promise<std::string> p;
        std::thread t(doSomething, std::ref(p));    //将创建的promise传进入
        t.detach();
            //create a future to process the outcome
        std::future<std::string> f(p.get_future());
        //process the outcome
        std::cout << "result: " << f.get() << std::endl;
    }
    catch (const std::exception& e) {
        std::cerr << "EXCEPTION: " << e.what() << std::endl;
    }
    catch (...) {
        std::cerr << "EXCEPTION " << std::endl;
    }
    cin.get();
    cin.get();
    return 0;
}

输入a的输出如下:

输入x的输出如下:

 

高级接口async(),不需要借助thread,直接来异步创建线程,

#include <future>
#include <list>
#include <iostream>
#include <exception>
using namespace std;

thread::id func()
{
    return this_thread::get_id();
}
int main()
{
    cout << "starting 2 tasks" << endl;
    cout << "- task1: process endless loop of memory consumption" << endl;
    cout << "- task2: wait for <return> and then for task1" << endl;
    auto f1 = async(func); // start task1() asynchronously (now or later or never)
            //返回一个future<thread::id>对象  //async有两种启动策略  一是马上异步执行 launch::async   一是延迟到调用get 函数才异步执行   launch::deferred

    cout << "\nwait for the end of task1: " << endl;
    try 
    {
        cout << f1.get(); //wait for task1() to finish (raises exception ifany)
                          //acquire the result
    }
    catch (const exception& e) 
    {
        cerr << "EXCEPTION: " << e.what() << endl;
    }
    cin.get();
    getchar();
    return 0;
}

 

async()的用法和bind()类似,只不过会异步执行而不需要再调用绑定之后的可调用对象。

 

函数和类的定义可以到MSDN的帮助文档里查,获取更全的,到 cplusplus.com/cppreference 网站上查。

 



 

  • 1
    点赞
  • 4
    收藏
    觉得还不错? 一键收藏
  • 1
    评论
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值