异步API中的std :: promise的生命周期问题

时间:2017-02-10 10:46:56

标签: c++ asynchronous std-future

我想知道如何使用promises和future开发异步API。 该应用程序使用单个数据流,用于未经请求的定期数据和请求/回复通信。

对于请求/回复阻止,直到收到回复不是一个选项,我不希望使用回调代码,所以我想写一些接受预期ID的SendMessage只在收到时回复并退出。由呼叫者来阅读回复。

候选API可以是:

std::future<void> sendMessage(Message msg, id expected)
{
   // Write the message
   auto promise = make_shared<std::promise<void>>();
   // Memorize the promise somewhere accessible to the receiving thread
   return promise->get_future();
 }

收到消息后,工作者线程应该能够查询数据结构,以确定是否有人在等待它并“释放”未来。

鉴于承诺不可重复使用,我想要了解的是我应该使用什么样的数据结构来管理“飞行中”的承诺。

1 个答案:

答案 0 :(得分:2)

此答案已被重写。

设置共享标志的状态可以让工作人员知道另一方(比如老板)是否还在期待结果。

共享标志以及promise和future可以包含在一个类(模板)中,比如Request。老板通过破坏他的请求副本来设置标志。并且工作人员通过在他自己的请求副本上调用某个成员函数来查询老板是否仍然期望完成请求。

标志上的同时读/写应该可能是同步的。

老板可能无法获得承诺,工人可能无法访问未来。

最多应该有两个请求副本,因为在销毁请求对象时会设置标志。为实现这一目标,我们可以将相应的成员函数视为deleteprivate,并提供构建请求的两个副本。

以下是请求的简单实现:

#include <atomic>
#include <future>
#include <memory>

template <class T>
class Request {
 public:
  struct Detail {
   std::atomic<bool> is_canceled_{false};
   std::promise<T> promise_;
   std::future<T> future_ = promise_.get_future();
  };

  static auto NewRequest() {
    std::unique_ptr<Request> copy1{new Request()};
    std::unique_ptr<Request> copy2{new Request(*copy1)};

    return std::make_pair(std::move(copy1), std::move(copy2));
  }

  Request(Request &&) = delete;

  ~Request() {
    detail_->is_canceled_.store(true);
  }

  Request &operator=(const Request &) = delete;
  Request &operator=(Request &&) = delete;

  // simple api
  std::promise<T> &Promise(const WorkerType &) {
    return detail_->promise_;
  }
  std::future<T> &Future(const BossType &) {
    return detail_->future_;
  }

  // return value:
  // true if available, false otherwise
  bool CheckAvailable() {
    return detail_->is_canceled_.load() == false;
  }

 private:
  Request() : detail_(new Detail{}) {}
  Request(const Request &) = default;

  std::shared_ptr<Detail> detail_;
};

template <class T>
auto SendMessage() {
  auto result = Request<T>::NewRequest();
  // TODO : send result.second(the another copy) to the worker
  return std::move(result.first);
}

新请求由factroy函数NewRequest构成,返回值为std::pair,其中包含两个std::unique_ptr,每个CheckAvailable()都包含新创建的请求的副本。

工作人员现在可以使用成员函数std::promise<T> &Promise(const WorkerType &)来检查请求是否被取消。

共享状态由std :: shared_ptr确实管理(我相信)。

关于std::future<T> &Future(const BossType &)的注意事项:const引用参数(根据您的实现应该用propre类型替换)是为了防止老板意外调用此函数,而工作者应该能够轻松提供用于调用此函数的propre参数。 dict2[1] = [dict1[val][0] if val in dict1 else val for val in dict2[1]] 也一样。