C++异步调用利器future/promise实现原理

前言在异步编程中,各种回调将让人眼花缭乱,代码分散,维护起来十分困难。boost和C++11 的 future/promise 提供了一个很好的解决方案,使得代码更加漂亮、易维护。在工作中,我也用过几次future/promise,但是还是十分生疏,所以决定学习下它的原理,用起来才更加顺畅。查了很多资料,发现很多语言都有这个机制,但是关于C++的promise的资料却很少,只有一些使用的教程,而没有
摘要由CSDN通过智能技术生成

前言

在异步编程中,各种回调将让人眼花缭乱,代码分散,维护起来十分困难。boost和C++11 的 future/promise 提供了一个很好的解决方案,使得代码更加漂亮、易维护。

在工作中,我也用过几次future/promise,但是还是十分生疏,所以决定学习下它的原理,用起来才更加顺畅。

查了很多资料,发现很多语言都有这个机制,但是关于C++的promise的资料却很少,只有一些使用的教程,而没有找到原理方面的。

“源码之前,了无秘密。”

所以还是决定从源码入手学习!

本文针对的源码是借鉴boost实现的版本,由于copyright的原因,就不贴出完整的源码了,需要学习的朋友可以参见boost的实现。

关于future/promise的简介,参见我之前写的一篇博文:

http://blog.csdn.net/jiange_zh/article/details/51602938

一、基于Future/Promise的异步同步化编程依赖的组件

  1. bind和callback,类似与boost库的bind和function;
  2. shared_ptr、scoped_ptr、tuple、exception,参考boost库中的shared_ptr、scoped_ptr、tuple、exception实现;
  3. Future和Promise,借鉴boost库的future设计思想;
  4. when_all,通过Future、Promise、tuple来实现,针对异步并行的同步化。

二、Function和Bind的用法

参见我之前写的一篇博文:

http://blog.csdn.net/jiange_zh/article/details/51598580

下面提到的bind类似于boost的bind,而Callback类似于Function,一般跟bind搭配使用。

三、shared_ptr、scoped_ptr、tuple

shared_ptr:引用计数。

scoped_ptr:不可转移所有权。

Tuple:很多的时候我们需要为函数返回多个值,我们可以使用class或struct来封装要返回的多个值,然后返回封装struct或class,但是使用这种方法的弊端就是增加的程序的代码量,最好是能通过一种匿名的struct或class来解决这个问题。Boost::tuple就为我们提供了一种类似于匿名struct的方法为我们解决函数的多个返回值的问题。既增强了代码的可读性又不增加代码量。其实std::pair就是boost::tuple的2个参数的特例,对boost::tuple你可以绑定更多的参数,或者你可以迭代实现无限多参数的情况。

四、EnableSharedFromThis

使用boost库时,经常会看到如下的类:

class A:public enable_share_from_this<A>

在什么情况下要使类A继承enable_share_from_this?

使用场合 :当类A被share_ptr管理,且在类A的成员函数里需要把当前类对象作为参数传给其他函数时,就需要传递一个指向自身的share_ptr。

我们就使类A继承enable_share_from_this,然后通过其成员函数 share_from_this()返回当指向自身的share_ptr。

以上有2个疑惑:

1.把当前类对象作为参数传给其他函数时,为什么要传递share_ptr呢?直接传递this指针不可以吗?

一个裸指针传递给调用者,谁也不知道调用者会干什么?假如调用者delete了该对象,而share_tr此时还指向该对象。

2.这样传递share_ptr可以吗?share_ptr< this >

这样会造成2个非共享的share_ptr指向一个对象,最后造成2次析构该对象。

boost官方文档中一个非常典型的例子:

http://www.boost.org/doc/libs/1_55_0/doc/html/boost_asio/tutorial/tutdaytime3/src.html

部分代码:

 1 class tcp_connection
 2   : public boost::enable_shared_from_this<tcp_connection>
 3 {
 4 public:
 5   typedef boost::shared_ptr<tcp_connection> pointer;
 6 
 7   static pointer create(boost::asio::io_service& io_service)
 8   {
 9     return pointer(new tcp_connection(io_service));
10   }
11 
12   tcp::socket& socket()
13   {
14     return socket_;
15   }
16 
17   void start()
18   {
19     message_ = make_daytime_string();
20 
21     boost::asio::async_write(socket_, boost::asio::buffer(message_),
22         boost::bind(&tcp_connection::handle_write, shared_from_this(),
23           boost::asio::placeholders::error,
24           boost::asio::placeholders::bytes_transferred));
25   }
26 
27 private:
28   tcp_connection(boost::asio::io_service& io_service)
29     : socket_(io_service)
30   {
31   }
32 
33   void handle_write(const boost::system::error_code& /*error*/,
34       size_t /*bytes_transferred*/)
35   {
36   }
37 
38   tcp::socket socket_;
39   std::string message_;
40 };

类tcp_connection继承enable_share_from_this,在22行里,它的成员函数start(),通过share_from_this返回指向自身的share_ptr。

五、Future和Promise

5.1 简介

Promise对象可保存T类型的值,该值可被future对象读取(可能在另一个线程中),这是promise提供的同步的一种手段。

在构造promise时,promise对象可以与共享状态关联起来,这个共享状态可以存储一个T类型或者一个由std::exception派生出的类的值,并可以通过get_future来获取与promise对象关联的对象,调用该函数之后,

  • 11
    点赞
  • 79
    收藏
    觉得还不错? 一键收藏
  • 10
    评论
C++中的异步调用可以使用std::async函数来实现。std::async函数返回一个std::future对象,该对象可以用于获取异步操作的结果。std::async函数有两个参数,第一个参数是std::launch枚举类型,用于指定异步操作的启动方式,可以是std::launch::async表示异步启动,也可以是std::launch::deferred表示延迟启动;第二个参数是一个可调用对象,可以是函数指针、函数对象或者Lambda表达式等。当使用std::launch::async启动异步操作时,std::async函数会在新线程中执行该可调用对象;当使用std::launch::deferred启动异步操作时,std::async函数会在调用get()函数时执行该可调用对象。 下面是一个示例程序,展示了std::async函数的使用方法和异步启动和延迟启动的区别: ``` #include <chrono> #include <future> #include <iostream> int main() { auto begin = std::chrono::system_clock::now(); auto asyncLazy = std::async(std::launch::deferred, [] { return std::chrono::system_clock::now(); }); auto asyncEager = std::async(std::launch::async, [] { return std::chrono::system_clock::now(); }); std::this_thread::sleep_for(std::chrono::seconds(1)); auto lazyStart = asyncLazy.get() - begin; auto eagerStart = asyncEager.get() - begin; auto lazyDuration = std::chrono::duration<double>(lazyStart).count(); auto eagerDuration = std::chrono::duration<double>(eagerStart).count(); std::cout << "asyncLazy evaluated after : " << lazyDuration << " seconds." << std::endl; std::cout << "asyncEager evaluated after: " << eagerDuration << " seconds." << std::endl; } ```
评论 10
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值