c++ - boost asio stable_timer上的多个递归async_wait
问题描述
这个问题的灵感来自 boost asio 文档(链接)中关于异步计时器的教程。代码稍作修改,效果更明显。
有一个相关的问题,Multiple async_wait from a boost Asio deadline_timer。但我不确定该问题的答案是否适用于我的情况。
代码非常简单,如果重复的行被注释掉,就可以按预期工作,如下所示。
A
steady_timer
与1s
通话持续时间async_wait
。当它到期时,将调用处理程序。在处理程序内部,定时器的生命周期再延长一秒,定时器
async_wait
再次调用。变量
count
20 用于限制计时器可以触发的次数。
#include <boost/asio.hpp>
#include <boost/bind.hpp>
#include <iostream>
namespace asio = boost::asio;
void bind_handler(const boost::system::error_code& ec,
asio::steady_timer& t,
int count) {
if (count > 0) {
std::cout << "getting " << count << "\n";
t.expires_at(t.expiry() + std::chrono::seconds(1));
t.async_wait(boost::bind(bind_handler, asio::placeholders::error,
boost::ref(t), --count));
}
}
int main() {
asio::io_context io_context(1);
asio::steady_timer t(io_context, std::chrono::seconds(1));
int count = 20;
t.async_wait(boost::bind(bind_handler, asio::placeholders::error,
boost::ref(t), count));
//t.async_wait(boost::bind(bind_handler, asio::placeholders::error,
// boost::ref(t), count));
auto start = std::chrono::steady_clock::now();
io_context.run();
auto end = std::chrono::steady_clock::now();
std::cout
<< std::chrono::duration_cast<std::chrono::seconds>(end - start).count()
<< " seconds passed\n";
return 0;
}
此代码的输出如下所示。每经过一秒就会打印一个新行。
getting 20
getting 19
getting 18
...lines...
...omitted...
getting 3
getting 2
getting 1
21 seconds passed
但是,如果上面代码中的两行未注释,则程序的行为会非常不同。输出粘贴在下面。该程序在一秒钟内打印所有行getting 20
,getting 1
然后在 40 秒内不显示任何内容,然后打印最后一行。
getting 20
getting 20
getting 19
getting 19
getting 18
getting 18
...lines...
...omitted...
getting 3
getting 3
getting 2
getting 2
getting 1
getting 1
41 seconds passed
我的问题是,多次递归调用如何async_wait
影响程序的行为?我觉得某种数据竞赛正在进行,但数字仍然按顺序打印。io_context
此外,正如我们在构造函数中看到的那样,只涉及一个线程。
解决方案
似乎该行为的答案在于以下文档basic_waitable_timer::expires_at(const time_point & expiry_time)
:
该函数设置到期时间。任何挂起的异步等待操作都将被取消。每个取消操作的处理程序将使用 boost::asio::error::operation_aborted 错误代码调用。
在您的示例中,当第一个计时器完成时,它会调用expires_at
以将计时器转发一秒。但是,这会取消第二个正在运行的 await 调用,现在将在下一个 eventloop 迭代中直接调用它,但会operation_aborted
出错。但是,由于您不检查错误代码ec
,因此您看不到。现在这个处理程序将再次直接转发计时器,从而取消上次async_wait
启动的计时器。
这种情况一直持续下去,直到处理程序经常取消自己,count==0
并且只有一个计时器在运行。由于过期日期已经每次转发1s,代码仍然等待整整40s过去。
推荐阅读
- python - 将 dm 发送给用户 discord.py 时出错
- javascript - 为什么这是一个无效的日期?
- bing - Bing Ads 刷新令牌 - 不会自动刷新
- spring-el - 在自定义注释中使用拼写时,inteliJ idea 不自动提示方法
- python - 在循环内并行化循环时,有没有办法解决“比较递归深度范围”?
- java - 由于 java.lang.NoClassDefFoundError: jdk/internal/reflect/GeneratedSerializationConstructorAccessor1 无法运行 gradle 测试任务
- docker - Docker Moodle localhost 不工作(CentOS)
- python - 用 ursina 进行左 clic 检测
- c# - 启用了可为空引用类型的 C# 事件 - 如何声明?
- excel - VBA - 根据特定顺序重命名工作表