c++ 之future和promise

future和promise可以配合使用,主要作用是在不同线程间传递数据。举个简单例子,直接看代码:

#include <iostream>
#include <future>
#include <thread>
#include <unistd.h>
 
void set_promise(std::promise<int>& p) {
    std::cout << "set_promise begin." << std::endl;
    sleep(1);
    p.set_value(100);
    std::cout << "set_promise end." << std::endl;
}
 
int main() {
    std::promise<int> p;
    // 将promise和future绑定,这一步就是允诺future,未来会有人对promise赋值
    std::future<int> f = p.get_future();
    std::thread t(&set_promise, std::ref(p));
    // 通过get 拿到promise set的value
    std::cout << f.get() << std::endl;
    t.join();
 
    return 0;
}

从这个代码可以看到主线程中声明了一个p,然后通过p.get_future()将promise和future绑定。再将promise变量传到set_promise线程中,在set_promise线程中对promise赋值。然后就可以在主线程中通过future的get获取promise设置的值。
运行结果:

x123@ubuntu:~/test$ ./test
set_promise begin.
set_promise end.
100

这里需要注意的一点是。如果set_promise线程迟迟没有对promise设置值,那主线程的future get会阻塞住。

其实这种方式完全可以应用在发送接收消息的案例中,下面可以举个apollo中实际应用promise和future的例子。apollo cyber中在client 发送和接收消息就是使用了promise和future。

可以简单看下apollo这块代码,完整代码大家可以从github上搜apollo获取。

template <typename Request, typename Response>
typename Client<Request, Response>::SharedFuture
Client<Request, Response>::AsyncSendRequest(SharedRequest request,
                                            CallbackType&& cb) {
  if (IsInit()) {
    std::lock_guard<std::mutex> lock(pending_requests_mutex_);
    sequence_number_++;
    transport::MessageInfo info(writer_id_, sequence_number_, writer_id_);
    request_transmitter_->Transmit(request, info);
    SharedPromise call_promise = std::make_shared<Promise>();
    // 将future和call_promise绑定
    SharedFuture f(call_promise->get_future());
    pending_requests_[info.seq_num()] =
        std::make_tuple(call_promise, std::forward<CallbackType>(cb), f);
    return f;
  } else {
    return std::shared_future<std::shared_ptr<Response>>();
  }
}

可以看到这里在发送请求的时候,就是声明了一个call_promise和一个future,并且通过call_promise->get_future()将future和promise绑定起来。然后再塞到pending_requests中,这里你可以理解AsyncSendRequest就是在线程1中执行,那promise的值在哪里设置?继续看下面代码:

template <typename Request, typename Response>
void Client<Request, Response>::HandleResponse(
    const std::shared_ptr<Response>& response,
    const transport::MessageInfo& request_header) {
  ADEBUG << "client recv response.";
  std::lock_guard<std::mutex> lock(pending_requests_mutex_);
  if (request_header.spare_id() != writer_id_) {
    return;
  }
  uint64_t sequence_number = request_header.seq_num();
  if (this->pending_requests_.count(sequence_number) == 0) {
    return;
  }
  // 从pending_requests_中 获取call_promise和future
  auto tuple = this->pending_requests_[sequence_number];
  auto call_promise = std::get<0>(tuple);
  auto callback = std::get<1>(tuple);
  auto future = std::get<2>(tuple);
  this->pending_requests_.erase(sequence_number);
  // 给call_promise设置上value
  call_promise->set_value(response);
  // 触发callback
  callback(future);
}

HandleResponse你可以理解也是个callback,是在别的线程中触发,暂时理解HandleResponse在线程2中触发吧,这里主要是拿到call_promise和future,并且给call_promise设置上value。那callback future后在哪里get呢? 继续看:

template <typename Request, typename Response>
typename Client<Request, Response>::SharedResponse
Client<Request, Response>::SendRequest(SharedRequest request,
                                       const std::chrono::seconds& timeout_s) {
  if (!IsInit()) {
    return nullptr;
  }
  auto future = AsyncSendRequest(request);
  if (!future.valid()) {
    return nullptr;
  }
  auto status = future.wait_for(timeout_s);
  if (status == std::future_status::ready) {
    return future.get();
  } else {
    return nullptr;
  }
}

这里在拿到future后,就可以直接通过future.get()获取刚才在线程2中设置的value值。

感兴趣的可以到github上看下apollo这块关于client封装的源码。

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值