修改活跃Boost Asio定时器过期时间未达预期问题求助
重启Boost Asio定时器未达预期效果
问题描述
我基于Boost Asio的steady_timer相关逻辑编写代码,尝试重启定时器,但实际输出与预期不符。
当前输出
0 : Start at 0 : ioContext.run() 1000 : on_timeout Timeout reached error=0 1100 : Too late, timer has already expired after 1100 ms 2200 : We managed to cancel the timer after 1100 ms 3300 : We managed to cancel the timer after 1100 ms ...
预期输出
0 : Start at 0 : ioContext.run() 1000 : on_timeout Timeout reached error=0 1000 : Too late, timer has already expired after 1100 ms 2000 : on_timeout Timeout reached error=0 2000 : Too late, timer has already expired after 1100 ms 3000 : on_timeout Timeout reached error=0 3000 : Too late, timer has already expired after 1100 ms ...
问题代码
#include <chrono> #include <functional> #include <iostream> #include <thread> #include <boost/asio.hpp> long int millis() { static long int offset = std::chrono::duration_cast<std::chrono::milliseconds>(std::chrono::system_clock::now().time_since_epoch()).count(); return std::chrono::duration_cast<std::chrono::milliseconds>(std::chrono::system_clock::now().time_since_epoch()).count() - offset; } class BoostAsioTimerEval { public: BoostAsioTimerEval(boost::asio::io_context& ioContext) : ioContext_(ioContext), timer_(ioContext_), interval_(std::chrono::milliseconds{1000}), lastMillis_(millis()) { timer_.expires_after(interval_); timer_.async_wait(std::bind(&BoostAsioTimerEval::on_timeout, this, std::placeholders::_1)); std::cout << millis() << " : Start at " << std::endl; } void on_event() { if (timer_.expires_after(interval_) > 0) { std::cout << millis() << " : We managed to cancel the timer after " << (millis() - lastMillis_) << " ms" << std::endl; timer_.async_wait(std::bind(&BoostAsioTimerEval::on_timeout, this, std::placeholders::_1)); } else { std::cout << millis() << " : Too late, timer has already expired after " << (millis() - lastMillis_) << " ms" << std::endl; // kick again timer_.expires_after(interval_); timer_.async_wait(std::bind(&BoostAsioTimerEval::on_timeout, this, std::placeholders::_1)); } lastMillis_ = millis(); } void on_timeout(const boost::system::error_code& error) { if (error != boost::asio::error::operation_aborted) { std::cout << millis() << " : on_timeout Timeout reached error=" << error.value() << std::endl; } else { std::cout << millis() << " : on_timeout Timeout aborted error=" << error.value() << std::endl; } } private: boost::asio::io_context& ioContext_; boost::asio::steady_timer timer_; std::chrono::milliseconds interval_; long int lastMillis_; }; int main(int argc, char** argv) { boost::asio::io_context ioContext; BoostAsioTimerEval boostAsioTimerEval(ioContext); std::thread worker([&]() { for (int i = 0; i < 10; ++i) { const int sleep = 1100; std::cout << millis() << " : sleep for " << sleep << " ms" << std::endl; std::this_thread::sleep_for(std::chrono::milliseconds(sleep)); boostAsioTimerEval.on_event(); } ioContext.stop(); }); std::cout << millis() << " : ioContext.run()" << std::endl; ioContext.run(); worker.join(); return 0; }
问题分析与解决方案
核心问题是定时器到期后未自动重启:第一次定时器在1000ms到期后,on_timeout仅输出日志,没有重新绑定异步等待,导致后续需要等到1100ms时on_event触发才重新设置定时器,打乱了1000ms的间隔节奏。同时lastMillis_的更新时机也不符合预期逻辑。
修改后的代码
#include <chrono> #include <functional> #include <iostream> #include <thread> #include <boost/asio.hpp> long int millis() { static long int offset = std::chrono::duration_cast<std::chrono::milliseconds>(std::chrono::system_clock::now().time_since_epoch()).count(); return std::chrono::duration_cast<std::chrono::milliseconds>(std::chrono::system_clock::now().time_since_epoch()).count() - offset; } class BoostAsioTimerEval { public: BoostAsioTimerEval(boost::asio::io_context& ioContext) : ioContext_(ioContext), timer_(ioContext_), interval_(std::chrono::milliseconds{1000}), lastMillis_(millis()) { restart_timer(); std::cout << millis() << " : Start at " << std::endl; } void on_event() { if (timer_.expires_after(interval_) > 0) { std::cout << millis() << " : We managed to cancel the timer after " << (millis() - lastMillis_) << " ms" << std::endl; restart_timer(); } else { std::cout << millis() << " : Too late, timer has already expired after " << (millis() - lastMillis_) << " ms" << std::endl; restart_timer(); } lastMillis_ = millis(); } void on_timeout(const boost::system::error_code& error) { if (error != boost::asio::error::operation_aborted) { std::cout << millis() << " : on_timeout Timeout reached error=" << error.value() << std::endl; lastMillis_ = millis(); restart_timer(); } else { std::cout << millis() << " : on_timeout Timeout aborted error=" << error.value() << std::endl; } } private: void restart_timer() { timer_.expires_after(interval_); timer_.async_wait(std::bind(&BoostAsioTimerEval::on_timeout, this, std::placeholders::_1)); } boost::asio::io_context& ioContext_; boost::asio::steady_timer timer_; std::chrono::milliseconds interval_; long int lastMillis_; }; int main(int argc, char** argv) { boost::asio::io_context ioContext; BoostAsioTimerEval boostAsioTimerEval(ioContext); std::thread worker([&]() { for (int i = 0; i < 10; ++i) { const int sleep = 1100; std::cout << millis() << " : sleep for " << sleep << " ms" << std::endl; std::this_thread::sleep_for(std::chrono::milliseconds(sleep)); boostAsioTimerEval.on_event(); } ioContext.stop(); }); std::cout << millis() << " : ioContext.run()" << std::endl; ioContext.run(); worker.join(); return 0; }
修改说明
- 封装
restart_timer函数:把设置到期时间和绑定异步等待的逻辑抽成独立函数,避免重复代码。 - 到期后自动重启:在
on_timeout的正常到期分支里,立即调用restart_timer,保证定时器持续按1000ms间隔触发。 - 修正
lastMillis_更新时机:在定时器实际到期时更新该值,确保时间差计算准确。
修改后,定时器会在每次到期后自动重启,即使on_event延迟调用,输出也会符合预期的间隔节奏。
内容的提问来源于stack exchange,提问作者Th. Thielemann
相关产品推荐
相关产品推荐

