在 boost::asio::io_service 上调用 run 时崩溃

Posted

技术标签:

【中文标题】在 boost::asio::io_service 上调用 run 时崩溃【英文标题】:Crash when calling run on boost::asio::io_service 【发布时间】:2014-05-28 02:50:06 【问题描述】:

我正在尝试编写一个相对简单的类“CallbackTimer”,它需要一定的时间和一个函数,并且在经过一段时间后调用该函数。如有必要,可以重复几次。

这一切都按预期工作,但是当我在计时器完成之前调用 start 几次时偶尔会崩溃,但我看不出问题出在哪里。我认为这是因为我没有正确混合我的线程和 io_service,但我不确定。任何帮助或指示将不胜感激。

类如下

CallbackTimer::CallbackTimer(const std::function<void()>& callback) :
  callback_(callback),
  currentRepeats_(0),
  //io_(boost::asio::io_service()),
  timer_(new boost::asio::deadline_timer(io_)),
  strand_(io_),
  thread_(nullptr)



CallbackTimer::~CallbackTimer()

  cancel();


void CallbackTimer::start(size_t intervalMillis, int repeats)

  if (thread_)
  
    cancel();
  

  requestedRepeats_ = repeats;
  intervalMillis_ = intervalMillis;
  currentRepeats_ = 0;
  runTimer();

  thread_.reset(new std::thread([this]()
  
    this->io_.run();
  ));

  thread_->detach();


void CallbackTimer::cancel()

  timer_->cancel();

  if (thread_ && thread_->joinable())
  
    thread_->join();
  

  io_.reset();


void CallbackTimer::runCallback(const boost::system::error_code& e)

  if (e == boost::asio::error::operation_aborted)
  
    io_.stop();
    return;
  

  currentRepeats_++;
  callback_();

  if (currentRepeats_ >= requestedRepeats_)
  
    io_.stop();
    return;
  

  runTimer();


void CallbackTimer::runTimer()

  timer_->expires_from_now(boost::posix_time::millisec(intervalMillis_));
  timer_->async_wait(strand_.wrap(std::bind(&CallbackTimer::runCallback, this, std::placeholders::_1)));

【问题讨论】:

【参考方案1】:

一目了然,有两个潜在的问题:

CallbackTimer 类无法保证io_service::reset() 在未完成对run()run_one()poll()poll_one() 的调用时不被调用的前提条件,导致未指定的行为. CallbackTimer::runCallback() 可以在 CallbackTimer 实例的生命周期结束后调用,从而调用未定义的行为。

这两个问题都是由于与运行io_service 的线程没有同步造成的。线程在CallbackTimer::start() 中创建后被分离,CallbackTimer::cancel() 中的 if 语句将始终为 false,导致不发生同步。这允许以下情况:

io_service::reset()thread_io_service::run() 内时被调用。 拥有io_serviceCallbackTimer 被释放,而thread_io_service::run() 内。

要解决此问题,请考虑不再与 thread_ 分离,以便可能发生同步。

为了进一步调试,堆栈跟踪或mcve 可以帮助确定崩溃的确切来源。

【讨论】:

你是对的,删除 detach 调用停止了崩溃。

以上是关于在 boost::asio::io_service 上调用 run 时崩溃的主要内容,如果未能解决你的问题,请参考以下文章

在 boost::asio::io_service 上调用 run 时崩溃

从作为分离线程运行的 boost::asio::io_service::work 捕获异常

boost::asio::io_service类

C++ boost::asio::io_service创建线程池thread_group简单实例

C++ boost::asio::io_service创建线程池thread_group简单实例

boost::asio io_service 停止特定线程