Boost :: asio - asio_handler_deallocate is called in io_service :: ~ io_service (), after io_service :: stop ()

I have ip::udp::socket built using io_service . There is only one boost::thread that calls the io_service::run() method and an io_service::work instance to prevent io_service::run() from returning. The completion handlers for my ip::udp::socket have the user functions asio_handler_allocate() and asio_handler_deallocate() , which are supported by my::custom_memory_pool .

When my application shuts down, this sequence of events occurs in my disconnected thread:

  • ip::udp::socket::close()
  • work::~work()
  • io_service::stop()
  • thread::join()
  • my::custom_memory_pool::~custom_memory_pool()
  • ip::udp::socket::~socket()
  • thread::~thread()
  • io_service::~io_service()

In step 8, calling io_service::~io_service() calls ...

 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 

So, io_service::~io_service() trying to free some memory into the pool that I destroyed in step 5.

I cannot move my::custom_memory_pool::~custom_memory_pool() after io_service::~io_service() .

I expected that after returning io_service::stop() and thread::join() there could be no more calls to asio_handler_deallocate() . Apparently, this is not so. What can I do in step 3 to force io_service delete all completion events and free up all the memory of its handler, and how can I block until io_service finishes these tasks?

+6
source share
2 answers

Here is the answer: when breaking io_service and its services, do not call io_service::stop() at all. Just work::~work() .

io_service::stop() is only valid for temporarily suspending io_service so that it can be io_service::reset() later. The usual graceful io_service termination io_service not include io_service::stop() .

+4
source

Calling io_service::stop() does not allow any handlers to be completed; it simply stops processing after any current handler and returns as soon as possible.

Since various internal structures are destroyed when the io_service destroyed, one solution is to control the order of destruction of the io_service relative to the user allocator. Either arrange them correctly if they are in the same structure (have a allocator up to io_service in the structure), or use a bunch and explicitly arrange their destruction to ensure that io_service is destroyed first.

+1
source

Source: https://habr.com/ru/post/900799/


All Articles