c++ 之future和promise

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

#include 
#include 
#include 
#include 
 
void set_promise(std::promise& 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 p;
    // 将promise和future绑定,这一步就是允诺future,未来会有人对promise赋值
    std::future 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 Client::SharedFuture
Client::AsyncSendRequest(SharedRequest request,
                                            CallbackType&& cb) {
  if (IsInit()) {
    std::lock_guard 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();
    // 将future和call_promise绑定
    SharedFuture f(call_promise->get_future());
    pending_requests_[info.seq_num()] =
        std::make_tuple(call_promise, std::forward(cb), f);
    return f;
  } else {
    return std::shared_future>();
  }
}

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

template 
void Client::HandleResponse(
    const std::shared_ptr& response,
    const transport::MessageInfo& request_header) {
  ADEBUG << "client recv response.";
  std::lock_guard 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 Client::SharedResponse
Client::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封装的源码。

你可能感兴趣的:(c++,开发语言)