gpt4 book ai didi

c++ - 将 Boost strand 与 std::future 结合使用

转载 作者:行者123 更新时间:2023-11-30 05:13:00 25 4
gpt4 key购买 nike

我遇到了一个用例,我想将 Boost strand 与 std::future 结合使用。

为了减少代码重复,我编写了一个通用函数,它将任务发布到 boost strand 并返回 future。

// Some definitions first...
typedef boost::asio::io_service::strand cb_strand;
typedef std::shared_ptr< cb_strand > cb_strand_ptr;

代码看起来像这样:

//////////////////////////////////////////////////////////////////////////
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;
};

然后我希望将 future 发布到 strand,如下例所示:

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)

阅读文档后,我想我明白什么是失信以及这种情况是如何发生的;但是,我觉得我正在捕捉 lambda 中的 promise ,所以一切都会好起来的。我是这个 lambda 世界的新手,所以我的理解可能有误。

  • Ubuntu 热情
  • GCC 6.3(使用 cmake 针对 C++14 配置)

最佳答案

您包装了任务,但您从不发布它。因此,被包装的任务会立即被销毁,而 promise 也会随之销毁。

还有一个陷阱,只有当你在一个不同的线程上运行 io_service 而不是为 future 阻塞的线程时,事情才有效......否则你已经创建了一个死锁:

既然您有多个线程,您需要首先避免服务在发布任务之前退出的竞争条件。

Bonus:

I'd suggest a far simpler take on the wrapper:

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

关于c++ - 将 Boost strand 与 std::future 结合使用,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/44169134/

25 4 0
Copyright 2021 - 2024 cfsdn All Rights Reserved 蜀ICP备2022000587号
广告合作:1813099741@qq.com 6ren.com