【问题标题】:Boost asio - stopping io_serviceBoost asio - 停止 io_service
【发布时间】:2011-06-16 01:58:53
【问题描述】:

我正在使用 boost::asio 进行一些非常基本的 UDP 数据包收集。 io_service 对象在工作线程中实例化,并从该线程内部调用 io_service.run()。我的问题是在我收集完数据包后让 io_service.run() 返回。

我不清楚在停止我的工作线程时可以从其他线程调用哪些 io_service 方法。我有一个对 io_service 对象的引用,我从另一个线程调用:

ios.dispatch( boost::bind( &udp_server::handle_kill, this ) );

在我的 udp_server 类中,该函数的处理程序从单个 boost::asio::ip::udp::socket 和单个 boost::asio::deadline_timer 对象中取消挂起的工作。两者都有待处理的异步工作。那时我调用 ios.stop():

void udp_server::handle_kill()
{
    m_socket.cancel();
    m_timer.cancel();
    m_ios.stop();
}

没有待处理的工作,我希望此时我对 ios.run() 的调用应该返回 - 但这不会发生。

那么为什么它不返回呢?对我来说最可能的解释是我不应该从另一个线程调用 io_service::dispatch() 。但是 dispatch() 方法似乎就是为此而构建的——在 io_service::run() 正在工作的线程中分派一个函数调用。它似乎就是这样做的。

所以这给我留下了一些相关的问题:

  1. 我是否正确使用了 io_service::dispatch()?
  2. 如果所有任务都被取消,io_service::run() 是否有任何理由不返回?
  3. socket::upd::cancel() 似乎不是关闭套接字并中止所有工作的正确方法。什么是正确的方法?

asio 对我来说表现不错,但我需要更好地了解这一架构。

更多数据

socket::udp::cancel() 显然是 Win32 下打开的套接字上不受支持的操作 - 所以这个操作会因抛出异常而失败 - 这实际上会导致退出 io_service::run(),但绝对是不是想要的出口。

socket::udp::close() 似乎没有取消挂起的 async_receive_from() 任务,因此调用它而不是 socket::udp::cancel() 似乎将线程留在 io_service::run ()。

【问题讨论】:

  • 您将handle_kill 发送到io_service 有什么原因吗?在该线程中调用handle_kill() 应该是安全的。如果你这样做,它仍然挂在run()吗?
  • 这是一个工作线程——它除了读取数据包之外什么都不做。杀死线程的动力来自GUI,它在另一个线程中。无论我使用哪种方法,都必须有一种线程安全的方式来与 io_service::run() 线程进行通信。在我看来, io_service::dispatch() 就是为这种需要而构建的。并且似乎确实在正确的线程中调用了 handle_kill()。
  • 您应该能够从任何线程停止io_service,无论它是否是该特定io_service 的工作线程。此外,dispatch()post() 是相同的,除了如果可能,dispatch() 可以立即调用内联函数(如果从io_service 线程调用dispatch)。因此,如果您知道您的dispatch() 调用将永远io_service 线程上,它与post() 相同。但这并不能解决您的问题。您是否可以提供一个 10-15 行的代码示例来重现该问题?
  • 我正在努力获得一个简短的例子来证明这一点。与此同时,我看到从另一个线程调用 ios::stop() 实际上会导致 ios:run() 以我想要的方式退出。我(现在仍然)不愿意在一个没有明确调用线程安全行为保证的方法上进行这样的调用,但它似乎确实有效。为什么我通过 dispatch() 的间接调用不起作用的问题仍有待复制和理解。
  • @MarkNelson,如果它足够,请接受提供的答案。

标签: c++ boost boost-asio


【解决方案1】:

从另一个线程调用io_service::stop 是安全的,这是文档中的well described

线程安全

不同的对象:安全。

共享对象:安全,具有 调用 reset() 时的异常 还有未完成的run()、run_one()、 poll() 或 poll_one() 调用导致 未定义的行为。

正如您的问题所表明的那样,您确实需要将其归结为一个可重复的示例。

【讨论】:

  • 我阅读了有关线程安全的说明,我不得不承认我对文档中的“共享对象”的含义有些无知。这似乎很笼统,但回想起来我认为你是对的,它描述得很好。这些知识并没有具体回答我的问题,但是因为它为我的错误的解决方法扫清了道路,所以它是下一个最好的事情。谢谢!
  • @Mark 如果您满意,请随时接受我对您问题的回答。您可能想针对您的错误发布一个新问题。
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 2017-09-17
  • 2012-11-26
  • 2011-12-18
  • 2015-04-22
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多