我遇到过一个用例,我希望将Boost链与std :: future结合使用。
为了减少代码重复,我编写了一个通用函数,它将任务发布到boost链并返回未来。
//////////////////////////////////////////////////////////////////////////
template <class Task>
auto post_future_to_strand(cb_strand_ptr apStrand, Task task)
{
using return_type = decltype(task());
auto promise = std::make_shared<std::promise<return_type>>();
auto future = promise->get_future();
apStrand->wrap
(
[promise, task]()
{
try
{
promise->set_value(task());
}
catch (...)
{
// LOG ERROR ...
// NOTE: Exceptions can be thrown when setting the exception!
try
{
promise->set_exception(std::current_exception());
}
catch (...)
{
//LOG ERROR ...
}
}
}
);
return future;
};
代码类似于:
std::future<int> f = post_future_to_strand(m_apStrand, std::bind(&foo::bar, this))
std::cout << "foo::bar() -> int is " << f.get() << std::endl;
然后,我希望将未来发布到以下示例中提供的链中:
terminate called after throwing an instance of 'std::future_error'
what(): std::future_error: Broken promise
Signal: SIGABRT (Aborted)
不幸的是,我收到了运行时异常:
scanf
阅读过文档之后,我想我明白了一个破碎的承诺是什么,以及情况是如何产生的;但是,我觉得我正在抓住lambda中的承诺,所以一切都应该好。我是这个lambdas世界的新手,所以也许我的理解是不对的。
答案 0 :(得分:1)
你包装任务,但你永远不会发布它。因此,包裹的任务会立即被破坏,并且具有承诺。
还有另一个陷阱,只有你在与阻止未来的线程不同的线程上运行io_service时,事情才有效...否则你创建了一个死锁:
现在您有多个线程,您需要避免在首先发布任务之前服务退出的竞争条件。
加成:
我建议对包装器采用更简单的方法:
template <typename Task> auto post_future_to_strand(cb_strand_ptr apStrand, Task task) { auto package = std::make_shared<std::packaged_task<decltype(task())()> >(task); auto future = package->get_future(); apStrand->post([package] { (*package)(); }); return future; }
<强> Live On Coliru 强>
#include <boost/asio.hpp>
#include <future>
#include <iostream>
using cb_strand_ptr = boost::asio::strand*;
//////////////////////////////////////////////////////////////////////////
template <typename Task>
auto post_future_to_strand(cb_strand_ptr apStrand, Task task)
{
auto package = std::make_shared<std::packaged_task<decltype(task())()> >(task);
auto future = package->get_future();
apStrand->post([package] { (*package)(); });
return future;
}
struct Foo {
boost::asio::strand s;
cb_strand_ptr m_apStrand = &s;
Foo(boost::asio::io_service& svc) : s{svc} {}
void do_it() {
std::future<int> f = post_future_to_strand(m_apStrand, std::bind(&Foo::bar, this));
std::cout << "foo::bar() -> int is " << f.get() << std::endl;
}
int bar() {
return 42;
}
};
int main() {
boost::asio::io_service svc;
auto lock = std::make_unique<boost::asio::io_service::work>(svc); // prevent premature exit
std::thread th([&]{ svc.run(); });
Foo foo(svc);
foo.do_it();
lock.reset(); // allow service to exit
th.join();
}
打印
foo::bar() -> int is 42