【问题标题】:boost::asio -- asio_handler_deallocate is called in io_service::~io_service(), after io_service::stop()boost::asio -- asio_handler_deallocate 在 io_service::~io_service() 中调用,在 io_service::stop() 之后
【发布时间】:2011-11-04 17:54:08
【问题描述】:

我有一个由io_service 构造的ip::udp::socket。只有一个boost::thread 调用io_service::run() 方法,还有一个io_service::work 实例以防止io_service::run() 返回。我的ip::udp::socket 的完成处理程序具有自定义的asio_handler_allocate()asio_handler_deallocate() 函数,它们由my::custom_memory_pool 支持。

当我的应用程序退出时,这一系列事件发生在我的关闭线程上:

  1. ip::udp::socket::close()
  2. work::~work()
  3. io_service::stop()
  4. thread::join()
  5. my::custom_memory_pool::~custom_memory_pool()
  6. ip::udp::socket::~socket()
  7. thread::~thread()
  8. io_service::~io_service()

在第 8 步中,对io_service::~io_service() 的调用导致...

Program terminated with signal 11, Segmentation fault.
#0  0x00000000005ad93c in my::custom_memory_pool<boost::aligned_storage<512u, -1u> >::deallocate (this=0x36323f8, t=0x7fca97a07880)
    at memory.hpp:82
82                      reinterpret_cast<pool_node*>(t)->next_ = head_;
(gdb) bt 30
#0  0x00000000005ad93c in my::custom_memory_pool<boost::aligned_storage<512u, -1u> >::deallocate (this=0x36323f8, t=0x7fca97a07880)
    at memory.hpp:82
#1  0x00000000005ad40a in asio_handler_deallocate (p=0x7fca97a07880, s=96, h=0x7fffe09d5480) at net.cpp:22
#2  0x0000000000571a07 in boost_asio_handler_alloc_helpers::deallocate<socket_multicast::completion_handler> (p=0x7fca97a07880, s=96, h=...)
    at /usr/include/boost/asio/detail/handler_alloc_helpers.hpp:51
#3  0x0000000000558256 in boost::asio::detail::reactive_socket_recvfrom_op<boost::asio::mutable_buffers_1, boost::asio::ip::basic_endpoint<boost::asio::ip::udp>, socket_multicast::completion_handler>::ptr::reset (this=0x7fffe09d54b0)
    at /usr/include/boost/asio/detail/reactive_socket_recvfrom_op.hpp:81
#4  0x0000000000558310 in boost::asio::detail::reactive_socket_recvfrom_op<boost::asio::mutable_buffers_1, boost::asio::ip::basic_endpoint<boost::asio::ip::udp>, socket_multicast::completion_handler>::do_complete (owner=0x0, base=0x7fca97a07880)
    at /usr/include/boost/asio/detail/reactive_socket_recvfrom_op.hpp:112
#5  0x0000000000426706 in boost::asio::detail::task_io_service_operation::destroy (this=0x7fca97a07880)
    at /usr/include/boost/asio/detail/task_io_service_operation.hpp:41
#6  0x000000000042841b in boost::asio::detail::task_io_service::shutdown_service (this=0xd4df30)
    at /usr/include/boost/asio/detail/impl/task_io_service.ipp:96
#7  0x0000000000426388 in boost::asio::detail::service_registry::~service_registry (this=0xd4a320, __in_chrg=<value optimized out>)
    at /usr/include/boost/asio/detail/impl/service_registry.ipp:43
#8  0x0000000000428e99 in boost::asio::io_service::~io_service (this=0xd49f38, __in_chrg=<value optimized out>)
    at /usr/include/boost/asio/impl/io_service.ipp:51

所以io_service::~io_service() 正在尝试将一些内存释放给我在第 5 步中销毁的池。

我无法将my::custom_memory_pool::~custom_memory_pool() 移动到io_service::~io_service() 之后。

我预计在io_service::stop()thread::join() 返回后,不会再有asio_handler_deallocate() 调用。显然情况并非如此。在第 3 步中我可以做什么来强制 io_service 将其所有完成事件出列并释放其所有处理程序内存,以及如何阻止直到 io_service 完成这些任务?

【问题讨论】:

  • 也许我应该将work::~work() 移动到io_service::stop() 之后...也许我没有给io_service 完成所有操作的机会。
  • 如果你明确地调用停止,那么当你破坏 work 是无关紧要的。该工作仅防止 io_service 在没有其他待处理任务时自动停止。
  • asio 文档:io_service::stop() 表示“对 run()、run_one()、poll() 或 poll_one() 的后续调用将立即返回。” work::~work() 意味着“io_service 对象的 run() 函数在工作进行时不会退出”这一要求的结束。所以我想得越多,似乎正确的顺序必须是io_service::stop() 然后是work::~work(),但是文档并没有明确说明。
  • 顺序无关。默认情况下,run() 仅在 io_service 停止或没有工作(work 对象或挂起的异步操作)可做时返回。通过添加work 对象,它可以防止后一种情况。显式调用 stop 导致 run/run_one/... 函数尽快返回,并进一步调用立即返回。然后调用io_service::reset() 将允许重新开始处理。这就是stop 不删除处理程序的原因,因为没有办法重新启动。

标签: c++ boost boost-asio


【解决方案1】:

答案如下:在拆除io_service 及其服务时,根本不要调用io_service::stop()。只需work::~work()

io_service::stop()实际上只是暂时挂起io_service,以便以后可能是io_service::reset()io_service 的普通正常关闭不应涉及 io_service::stop()

【讨论】:

  • 这个答案是完全错误的。 stop() 和 ~work() 不做同样的事情。 ~work() 完成所有待处理的工作,这可能需要(可能无限)时间,而 stop() 取消在异步操作上阻塞的调用。如果你终止你的应用程序,你想调用 stop() 原因很明显(程序必须尽快终止)。
  • 你确定@Kenji 吗? stop() 不会取消任何 I/O 调用,它只会取消 Stop the io_service object's event processing loop。关于 stop() 的用途还有很多话要说,但我认为“完全错误”有点言过其实。 ——詹姆斯·布洛克
  • 是的@James,它不会取消 I/O 调用/待处理的工作。它只是让所有被 run() 等调用阻塞的线程尽快退出函数。与此同时,我实际上了解到,在销毁 io_service 之前,您不能调用 io_service::stop(),因为库有时会出现段错误 - 它无法清理其余未决操作。很遗憾,但显然“按预期工作”,因为图书馆的专家用户向我保证 - 他们还说这种行为已记录在案,但我在任何地方都没有找到它。所以真的没有简单而理智的方法来结束 io_service。
  • whereas stop() cancels calls blocked on asynchronous operations 我的意思是它取消(返回)run() 调用,这些调用因为有待处理的工作而被阻塞。
【解决方案2】:

调用io_service::stop() 不允许它完成任何处理程序,它只是在任何当前运行的处理程序之后停止处理并尽快返回。

由于在销毁io_service时会销毁各种内部结构,因此一种解决方案是控制io_service相对于自定义分配器的销毁顺序。如果它们在同一个结构中(在结构中的 io_service 之前有分配器),要么正确排序它们,要么使用堆并显式排序它们的销毁以保证 io_service 首先被销毁。

【讨论】:

  • +1 确实,io_service::stop() 将强制io_service::run() 立即返回,并且io_service 中的任何入队完成处理程序都将持续存在,并且可能会在稍后出列,在io_service::reset() 之后。我对此进行了测试。
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2017-09-17
  • 1970-01-01
  • 2011-06-16
  • 2012-11-26
  • 2011-12-18
  • 1970-01-01
相关资源
最近更新 更多