IO服务重新启动后,Boost最后期限计时器持续触发

Boost deadline timer fires continuously after IO service restart

本文关键字:计时器 最后 重新启动 服务 Boost IO      更新时间:2023-10-16

我正在编写一些命令代码,对此我需要一个常规计时器进行监控。我使用boost ASIO进行通信,所以我决定使用最后期限计时器进行计时,并将其放在同一个IO服务上。

第一次运行代码时一切都很好,但一旦通信(在我的情况下是串行端口(停止并重新启动,就会出错。计时器开始失灵,通讯中断。我相信这两者是相关的,所以我只关注这个问题的计时器。

请考虑下面的代码。这应该启动一个计时器,让它运行10秒,停止计时器,然后再启动它10秒。然而,实际发生的情况是,当计时器重新启动时,它会连续启动(两次启动之间没有任何延迟(。

#include <iostream>
#include <thread>
#include <boost/bind.hpp>
#include <boost/asio.hpp>
boost::posix_time::ptime timer_start_;
void CallbackTimerFunc(boost::asio::deadline_timer* timer) {
auto time_since_start = timer->expires_at() - timer_start_;
std::cout << "It's been " << time_since_start.total_seconds() << " seconds." << std::endl;
// Sleep is here to prevent spamming when timer starts malfunctioning.
usleep(20000);
timer->expires_at(timer->expires_at() + boost::posix_time::milliseconds(1000));
timer->async_wait(boost::bind(&CallbackTimerFunc, timer));
}
int main(int /*argc*/, char** /*args*/) {
// Start
boost::asio::io_service io_service_;
boost::asio::deadline_timer deadline_timer_(io_service_);
deadline_timer_.expires_from_now(boost::posix_time::milliseconds(1000));
timer_start_ = deadline_timer_.expires_at();
deadline_timer_.async_wait(boost::bind(&CallbackTimerFunc, &deadline_timer_));
std::thread io_thread_(boost::bind(&boost::asio::io_service::run, &io_service_));
// Stop
sleep(10);
io_service_.stop();
while (!io_service_.stopped()) usleep(10000);
deadline_timer_.cancel();
io_thread_.join();
std::cout << "******************************" << std::endl;
// Restart
io_service_.restart();
deadline_timer_.expires_from_now(boost::posix_time::milliseconds(1000));
timer_start_ = deadline_timer_.expires_at();
deadline_timer_.async_wait(boost::bind(&CallbackTimerFunc, &deadline_timer_));
io_thread_ = std::thread(boost::bind(&boost::asio::io_service::run, &io_service_));
// Stop
sleep(10);
io_service_.stop();
while (!io_service_.stopped()) usleep(10000);
deadline_timer_.cancel();
io_thread_.join();
return 0;
}

预期的输出是计时器两次计数到10(实际上是从0到8(。实际输出是,它一次计数到10,然后就失控了,声称数百秒已经过去了。

我可以通过创建一个全新的IO服务和计时器来让这些代码发挥作用,但考虑到它们应该是可重用的,这似乎没有必要。

如果有人能告诉我这里发生了什么,或者至少能重现我的结果,我将不胜感激

感谢@tkausl让我走上正轨。这是更正后的代码。注意CallbackTimerFunc顶部的额外检查。

#include <iostream>
#include <thread>
#include <boost/bind.hpp>
#include <boost/asio.hpp>
boost::posix_time::ptime timer_start_;
void CallbackTimerFunc(const boost::system::error_code& error, boost::asio::deadline_timer* timer) {
if (error.value() == boost::asio::error::operation_aborted) {
std::cout << "Abort was sent on the first firing. Because of course it would be. Ignoring it will fix the problem. Because of course it will." << std::endl;
return;
}
auto time_since_start = timer->expires_at() - timer_start_;
std::cout << "It's been " << time_since_start.total_seconds() << " seconds." << std::endl;
// Sleep is here to prevent spamming when timer starts malfunctioning.
usleep(20000);
timer->expires_at(timer->expires_at() + boost::posix_time::milliseconds(1000));
timer->async_wait(boost::bind(&CallbackTimerFunc, boost::asio::placeholders::error, timer));
}
int main(int /*argc*/, char** /*args*/) {
// Start
boost::asio::io_service io_service_;
boost::asio::deadline_timer deadline_timer_(io_service_);
deadline_timer_.expires_from_now(boost::posix_time::milliseconds(1000));
timer_start_ = deadline_timer_.expires_at();
deadline_timer_.async_wait(boost::bind(CallbackTimerFunc, boost::asio::placeholders::error, &deadline_timer_));
std::thread io_thread_(boost::bind(&boost::asio::io_service::run, &io_service_));
// Stop
sleep(10);
io_service_.stop();
while (!io_service_.stopped()) usleep(10000);
deadline_timer_.cancel();
io_thread_.join();
std::cout << "******************************" << std::endl;
// Restart
io_service_.restart();
deadline_timer_.expires_from_now(boost::posix_time::milliseconds(1000));
timer_start_ = deadline_timer_.expires_at();
deadline_timer_.async_wait(boost::bind(CallbackTimerFunc, boost::asio::placeholders::error, &deadline_timer_));
io_thread_ = std::thread(boost::bind(&boost::asio::io_service::run, &io_service_));
// Stop
sleep(10);
io_service_.stop();
while (!io_service_.stopped()) usleep(10000);
deadline_timer_.cancel();
io_thread_.join();
return 0;
}