c++11 std::async使用注意

    std::async,c++11中提供的异步任务高级抽象,包含在 <future>头文件中,能让你方便的实现异步地执行一个任务

并在需要地时候获取其结果。和直接使用std::thread 相比,有着一些优势:

  1.std::async 返回的future对象,可以方便地等待callable对象执行完成并获取其返回值

  2.能从实现库的一些高级功能中获益,比如线程池等,并大大减少异常的产生。

当然其使用更简洁。但是async存在着一些问题,使用的时候要小心。

1.async的启动策略,两种启动策略 std::launch::async , std::launch::deferred

如果不指定,将采用默认的启动策略,等同于 launch::async | launch::deferred

并且标准中没有规定默认采用哪种策略,有实现库自己决定,测试VS2013中默认方式为async而gcc4.8.2为deferred。

在使用时就要注意。如果为launch::deferred模式,那么永远不会启动新线程去执行,直到你调用 wait 或 get时

才在你的当前线程中去执行callable对象。如果你需要让callable立即启动线程去执行,那么一定要

在调用async时指定launch::async,可以使用一个简单的包装避免忘记:

template <typename F, typename... Args>
inline auto real_async(F&& f, Args&&... args)
  -> std::future<typename std::result_of<F(Args...)>::type>
{
    return std::async(std::launch::async, 
		      std::forward<F>(f), 
		      std::forward<Args>(args)...);
}

2.std::async返回的future对象

以下代码存在一个问题

void work_proc()
{
    vector<int> numbers;
    ...   //do something
    real_async(some_proc,  std::move(numbers));
}

在当前线程中调用了work_proc,希望让单独的一个线程去处理一些不关心结果的耗时的事情,然后

当前线程再去处理一些其他的任务。然而事情不一定如你期待那样。实际上在vs2013上一切表现如

预期,在gcc4.8.2测试,会一直阻塞在work_proc中,直到some_proc执行完成。

在标准库中有说明,在std::future的析构函数中:

~future();
 (since C++11)
   

Releases any shared state. This means

  • if the return object or provider holds the last reference to its shared state, the shared state is destroyed; and
  • the return object or provider gives up its reference to its shared state; and

  • these actions will not block for the shared state to become ready, except that it may block if all of the following are true: the shared state was created by a call to std::async, the shared state is not yet ready, and this was the last reference to the shared state.

注意第三条:在以下三个条件全部满足时future析构可能阻塞

(1)共享状态是由调用std::async时创建的

(2)共享状态还不是ready状态

(3)被析构的当前对象持有着对共享状态的最后一个引用

而work_proc函数中的情况刚好全部满足。然而不幸的是如果你仍然想用async,并且忽略其返回,是没办法避免阻塞的。

但是还是有办法实现相同的目的,使用std::packaged_task和std::thread.

template <typename F, typename... Args>
auto really_async2(F&& f, Args&&... args)
-> std::future<typename std::result_of<F(Args...)>::type>
{
    using _Ret = typename std::result_of<F(Args...)>::type;
    auto _func = std::bind(std::forward<F>(f), std::forward<Args>(args)...);
    std::packaged_task<_Ret()> tsk(std::move(_func));
    auto _fut = tsk.get_future();
    std::thread thd(std::move(tsk));
    thd.detach();
    return _fut;
}


评论 6
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值