此答案已被改写。
设置共享标志的状态可以使工作人员知道对方,比如老板,是否仍在期待结果。
共享标志以及承诺和未来可以包含在一个类(模板)中,比如请求。老板通过破坏他的请求副本来设置标志。工人通过在他自己的请求副本上调用某些成员函数来查询老板是否仍然期望请求完成。
标志上的同时读/写应该可能是同步的。
老板可能无法获得承诺,工人可能无法获得未来。
请求最多应该有两个副本,因为在销毁请求对象时会设置标志。为此,我们可以将相应的成员函数定义为delete
or private
,并在构造时提供两个请求副本。
下面是请求的简单实现:
#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);
}
新请求由工厂函数构造NewRequest
,返回值为a std::pair
,其中包含两个std::unique_ptr
,每个都保存新创建的请求的副本。
worker 现在可以使用成员函数CheckAvailable()
来检查请求是否被取消。
并且共享状态由 std::shared_ptr 正确管理(我相信)。
注意std::promise<T> &Promise(const WorkerType &)
: const 引用参数(应该根据你的实现替换为适当的类型)是为了防止老板意外调用这个函数,而工人应该能够轻松地提供一个适当的参数来调用这个函数。对于std::future<T> &Future(const BossType &)
.