Таймер повышения крайнего срока срабатывает непрерывно после перезапуска службы ввода-вывода - PullRequest
0 голосов
/ 04 ноября 2019

Я работаю над кодом связи, для которого мне нужен обычный таймер для мониторинга. Я использую повышение ASIO для связи, поэтому я решил использовать таймер крайнего срока для синхронизации и установить его на тот же сервис ввода-вывода.

Все работает отлично при первом запуске кода, но однажды он работает неправильносвязь (в моем случае последовательный порт) останавливается и перезапускается. Таймер начинает работать со сбоями, и связь обрывается. Я полагаю, что они связаны между собой, поэтому я просто сосредоточился на таймере для этого вопроса.

Рассмотрим код ниже. Это должно запустить таймер и дать ему поработать в течение 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 раз, а затем просто теряет сознание, утверждая, что проходят сотни секунд.

Я могу заставить этот код работать, создав совершенно новый сервис ввода-вывода и таймер, но это похоже надолжно быть ненужным, учитывая, что они должны быть многоразовыми.

Если кто-нибудь может сказать мне, что здесь происходит или хотя бы воспроизвести мои результаты, я был бы признателен.

1 Ответ

0 голосов
/ 04 ноября 2019

Спасибо @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;
}
...