gpt4 book ai didi

c++ - boost.Asio 在幕后执行什么处理程序?

转载 作者:行者123 更新时间:2023-11-30 01:42:01 26 4
gpt4 key购买 nike

我有一个非常简单的 Boost.Asio 案例:一个由 deadline_timer 保护的 async_read。我还有一个 std::atomic_bool DEBUG[2]async_read 处理程序设置 DEBUG[0]deadline_timer 设置 DEBUG[1]。这是无条件发生的,即使错误代码是 error::operation_aborted

现在,当我调用 io_service::run_one() 时,我通常会看到其中一个 DEBUG 指示器集。然而,在至少 10% 的情况下,run_one 返回 1 但两个指示器均未设置,即两个处理程序均未被调用。 (还缺少处理程序的其他副作用)。

现在 run_one 应该返回执行的处理程序的数量,所以当它返回 1 时它一定已经执行了一个处理程序 - 但如果不是我的,那是哪个处理程序?

我问的原因是因为即使在 .reset() 之后,io_service 对象也会损坏。

相关代码 - 相当冗长以明确问题:

boost::asio::deadline_timer deadline(thread_io_service);
deadline.expires_from_now(boost::posix_time::seconds(timeoutSeconds));
read_counter += 2; // Initialized to 1 in ctor, so always odd.
// C++11: Cannot capture expressions such as this->read_counter.
unsigned read_counter_copy = read_counter;
read_timeout.store(0, std::memory_order_release); // 0 = no timeout.
deadline.async_wait([&, read_counter_copy](boost::system::error_code const&)
{
// read_counter_copy is very intentionally captured by value - this timeout applies only to the next read.
read_timeout.store(read_counter_copy, std::memory_order_release);
DEBUG[0] = true;
}
);

// Start reading "asynchronously", wait for completion or timeout:
std::atomic<boost::system::error_code> ec(boost::asio::error::would_block);
size_t len = 0;

boost::asio::async_read(socket, boost::asio::buffer(buffer + byteShift), boost::asio::transfer_exactly(nrBytes),
[&](boost::system::error_code const& err, size_t bytesTransferred)
{
len = bytesTransferred;
ec.store(err, std::memory_order_release);
DEBUG[1] = true;
}
);

// We only have 5 states to deal with
enum { pending, timeout, read, read_then_timeout, timeout_then_read } state = pending;
for (;;)
{
if (state == read_then_timeout) assert(false); // unreachable - breaks directly
else if (state == timeout_then_read) assert(false); // unreachable - breaks directly
// [pending, read, timeout] i.e. only one handler has run yet.
thread_io_service.run_one(); // Don't trust this - check the actual handlers and update state accordingly.
if (state == pending && read_timeout.load(std::memory_order_acquire) == read_counter)
{
state = timeout;
socket.cancel(); // This will cause the read handler to be called with ec=aborted
continue;
}
if (state == read && read_timeout.load(std::memory_order_acquire) == read_counter)
{
state = read_then_timeout;
break; //
}
if (state == pending && ec.load(std::memory_order_acquire) != boost::asio::error::would_block)
{
state = read;
deadline.cancel();
continue;
}
if (state == timeout && ec.load(std::memory_order_acquire) != boost::asio::error::would_block)
{
state = timeout_then_read; // Might still be a succesfull read (race condition)
break;
}
// This is the actual problem: neither read nor timeout.
// DEBUG == {false,false} when this happens.
L_NET(warning) << "Boost.Asio spurious return";
}
assert(state == timeout_then_read || state == read_then_timeout);
thread_io_service.reset();

最佳答案

如果您使用 async_read 读取 TCP 流,它会在内部设置 async_read_some 内部处理程序,当它返回时会检查到目前为止的数据和/或接收到的数据量,并在完成或错误时调用您的处理程序,或再次调用 async_read_some

然而,我对损坏的 io_service 感到惊讶,但这可能取决于您调用重置的位置。实际上,如果您在仍然存在处理程序时调用 reset(),并且在 lambda 中捕获的引用超出范围后,您可能会调用 UB。

关于c++ - boost.Asio 在幕后执行什么处理程序?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/40283753/

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