等待助推器asio的未来在io_service.stop()之后永远持续下去
Waiting boost asio's future lasts forever after io_service.stop()
我尝试等待从任何boost::asio::async_
函数返回的std::future
对象(使用 use_future
)。例如:
auto endpoint_future = resolver.async_resolve(query, boost::asio::use_future);
endpoint_future.wait(); // lasts forever after io_service.stop();
这是在一个线程中完成的。我还有另一个线程在此async_resolve
调用之前启动:
runner_ = std::thread([this]() {
boost::asio::io_service::work work(io_service_);
io_service_.run();
});
一切正常,但后来我还添加了一个boost::asio::deadline_timer
来停止任何与io_service
的工作:
void deadlineTimeout() {
deadline_.cancel();
io_service_.stop();
// closing socket here does not work too
}
但是,deadlineTimeout()
当截止日期达到时,它会超时并且它会执行io_service_.stop()
未来没有被释放,因此endpointer_future.wait()
仍然阻塞。在这种情况下,我怎样才能停止等待未来?
我自己找到了一个解决方案:我们不需要stop()
io_service
而是reset()
它,在此之前我们需要关闭套接字,因此正确的超时回调将是:
void deadlineTimeout() {
deadline_.cancel();
socket_.close(); // socket_ is a socket on io_service_
io_service_.reset();
}
在此更改之后,所有期货都将被释放。
对io_sevice.stop()
的调用将导致所有run()
和run_one()
的调用尽快返回。 从处理程序中调用时,调用方将从run()
返回,而不调用任何其他处理程序。 在您的情况下,async_resolve
的完成处理程序将设置与endpoint_future
关联的promise
;但是,通过停止io_service
,将不会调用完成处理程序。 请考虑以下任一情况:
-
cancel()
与future
关联的 I/O 对象,然后继续运行io_service
直至完成,以便设置promise
的值 - 销毁所有 I/O 对象,然后销毁
io_service
以便删除处理程序并由future
检测到已损坏的承诺
循环 对未来执行定时等待,如果未来已准备就绪或
io_service
已停止,则退出循环。 例如,以下函数返回一个boost::optional
,其中包含未来或boost::none
如果不会设置未来,则返回该值。template <typename T> boost::optional<T> get( boost::asio::io_service& io_service, std::future<T>& future) { for (;;) { // If the future is ready, get the value. if (future.wait_for(std::chrono::seconds(1)) == std::future_status::ready) { return {future.get()}; } // Otherwise, if the future is never going to be set, return none. if (io_service.stopped()) { return {boost::none}; } } } ... if (auto endpoint_iterator = get(io_service, endpoint_future)) { // use *endpoint_iterator... }
下面是一个示例,演示如何在停止io_service
的同时安全地等待未来:
#include <chrono>
#include <iostream>
#include <thread>
#include <boost/asio.hpp>
#include <boost/asio/use_future.hpp>
#include <boost/optional.hpp>
template <typename T>
boost::optional<T> get(
boost::asio::io_service& io_service,
std::future<T>& future)
{
for (;;)
{
// If the future is ready, get the value.
if (future.wait_for(std::chrono::seconds(1)) == std::future_status::ready)
{
return {future.get()};
}
// Otherwise, if the future is never going to be set, return none.
if (io_service.stopped())
{
std::cout << "io_service stopped, future will not be set" << std::endl;
return {boost::none};
}
std::cout << "timeout waiting for future" << std::endl;
}
}
int main()
{
boost::asio::io_service io_service;
// Create I/O objects.
boost::asio::ip::udp::socket socket(io_service,
boost::asio::ip::udp::v4());
boost::asio::deadline_timer timer(io_service);
// Process the io_service in the runner thread.
auto runner = std::thread([&]() {
boost::asio::io_service::work work(io_service);
io_service.run();
});
// Start an operation that will not complete.
auto bytes_transferred_future = socket.async_receive(
boost::asio::null_buffers(), boost::asio::use_future);
// Arm the timer.
timer.expires_from_now(boost::posix_time::seconds(2));
timer.async_wait([&](const boost::system::error_code&) {
timer.cancel();
socket.close();
io_service.stop();
});
// bytes_transferred's promise will never be set as the io_service
// is not running.
auto bytes_transferred = get(io_service, bytes_transferred_future);
assert(!bytes_transferred);
runner.join();
}
使工作在截止时间超时时可见,并允许截止时间超时将其删除。
boost::scoped_ptr<boost::asio::io_service::work work;
您仍然可以在此处创建工作,但要分配堆。
runner_ = std::thread([this]() {
work = new boost::asio::io_service::work(io_service_);
io_service_.run();
});
并像这样关闭:
void deadlineTimeout() {
deadline_.cancel();
socket_.close(); // socket_ is a socket on io_service_
work.reset();
// The io_service::run() will exit when there are no active requests
// (i.e. no sockeet, no deadline, and no work)
// so you do not need to call: io_service_.stop();
}
- 为什么在popback()操作之后,它仍然打印完整的矢量
- 在类定义之后定义一个私有方法
- 在循环C++中指定字符串之后,不会打印该字符串
- C++宏忽略之后的内容
- 要与"if constexpr"一起使用的编译时消息(在预处理器之后)
- 为什么是谷神星协方差.计算()似乎永远运行而不返回?
- strncpy之后的char数组的错误行为
- 计算十进制 c++ 之后的数字
- 密码登录程序将永远循环并显示不正确的结果
- "x += x--"之后的 x 是什么?
- 类的前向声明之后的类成员函数定义,在类声明之前
- 为什么将双精度转换为 int 似乎在第 16 位数字之后将其四舍五入?
- 我想在C++中读取一些多个字符,但它永远不会读取第二个字符
- SFML 碰撞永远不会在我的系统中注册
- execlp() 在 fork() 之后无法正常工作
- 我认为我的代码很好,但它在 cin a 之后停止并且没有进一步?
- 如何在MISRA C++之后实施CRTP
- 在 OpenCV 的 namedWindow 之前或之后初始化 Tesseract
- 等待助推器asio的未来在io_service.stop()之后永远持续下去
- 虽然循环中断,但之后的代码永远不会执行