从多个源文件/线程中提升asio io_service多个对象 - 在wake_one_idle_thread_and_unlock中崩溃

时间:2017-08-28 16:52:46

标签: boost boost-asio

在已经为udp socket使用boost asio的应用程序中看到一个无法解释的崩溃(在程序的某些部分) - 添加一些新类以在程序的其他部分使用boost asio截止时间计时器。

甚至在实例化新类之前 - 程序在现有的udp套接字实例化中崩溃 - 当从该app类调用io_service构造函数时。

如果我禁用(要么禁用udp套接字功能),要么在新类的程序中完全不相关的部分中使用截止时间计时器禁用新功能 - 它可以正常工作。

但两者似乎都无法共存

任何已知的问题围绕来自不同线程的io_service对象的多个实例化,或者更可能是我对io_service的使用不正确? 虽然在使用io_service / timers的新类尚未构建时触发seg错误非常奇怪。

以下是崩溃的日志:

#0  wake_one_idle_thread_and_unlock (lock=..., this=0x214ea20) at /x//boost/asio/detail/impl/task_io_service.ipp:461
#1  boost::asio::detail::task_io_service::wake_one_thread_and_unlock (this=0x214ea20, lock=...) at /x//boost/asio/detail/impl/task_io_service.ipp:472
#2  0x00007fff6bc16c1a in init_task (this=0x214ea20) at /x///boost/asio/detail/impl/task_io_service.ipp:118
#3  init_task (this=<optimized out>) at /x///boost/asio/detail/impl/epoll_reactor.ipp:145
#4  reactive_socket_service_base (io_service=..., this=0x214e648) at /x//vendors/boost/1.48.0/linux-x86_64/Release/common/include/boost/asio/detail/impl/reactive_socket_service_base.ipp:34
#5  reactive_socket_service (io_service=..., this=0x214e648) at /x///boost/asio/detail/reactive_socket_service.hpp:77
#6  datagram_socket_service (io_service=..., this=0x214e620) at /x//boost/asio/datagram_socket_service.hpp:89
#7  boost::asio::detail::service_registry::create<boost::asio::datagram_socket_service<boost::asio::ip::udp> > (owner=...) at /x///boost/asio/detail/impl/service_registry.hpp:81
#8  0x00007fff6bc12a32 in do_use_service (factory=0x7fff6bc16a20 <boost::asio::detail::service_registry::create<boost::asio::datagram_socket_service<boost::asio::ip::udp> >(boost::asio::io_service&)>, key=<synthetic pointer>, this=0x214f000)
    at /x///boost/asio/detail/impl/service_registry.ipp:123
#9  use_service<boost::asio::datagram_socket_service<boost::asio::ip::udp> > (this=0x214f000) at /x///boost/asio/detail/impl/service_registry.hpp:48
#10 use_service<boost::asio::datagram_socket_service<boost::asio::ip::udp> > (ios=...) at /x///boost/asio/impl/io_service.hpp:33
#11 basic_io_object (io_service=..., this=0x214e960) at /x///boost/asio/basic_io_object.hpp:183
#12 basic_socket (io_service=..., this=0x214e960) at /x///boost/asio/basic_socket.hpp:69
#13 basic_datagram_socket (io_service=..., this=0x214e960) at /x///boost/asio/basic_datagram_socket.hpp:69
#14 (this=this@entry=0x214e930, __in_chrg=<optimized out>, __vtt_parm=<optimized out>) at /app.cpp:18

2 个答案:

答案 0 :(得分:2)

  

甚至在实例化新类之前 - 程序在现有的udp套接字实例化中崩溃 - 当从该app类调用io_service构造函数时。

这给了我一个想法。真的,你说的是不存在运行时干扰。

这意味着我们应该关注链接时干扰。

只有在ODR违规发生时才会发生这种情况。

如果“使用ASIO for UDP”的部分(让我们称之为“UDP部分”)使用不同版本的标头,不同的编译器和/或不同的编译标志进行编译,您可能会得到已知的内容as ODR violations :违反单一定义规则

在链接时,编译器可以自由地删除源自不同翻译单元的相同符号的副本。但是,如果它们实际上不相同(因为ODR违规),使用的“其他”副本会导致Undefined Behaviour,这可能表现为崩溃²。

因此,除非您可以控制“UDP部分”的编译方式,否则请确保符合 的构建方式,或者不要以冲突的方式链接。我相信使用严格管理的可见性共享链接可以隐藏在库的任一部分的实现中涉及的Boost符号。当然,这假设那些Boost类型不是公共接口的一部分。

¹(因为Asio只是标题,所以不能真正存在冲突的共享库版本,尽管如果你动态链接Boost System,请检查它是否与版本匹配,构建工具链和构建用于使用asio for UDP的部分。)

²如果你很幸运,实际上:任何事情都可能发生,包括看似工作正常但腐败的数据,约会你的女儿或将你的金鱼卖给摩洛哥牙齿仙女

答案 1 :(得分:0)

我会写下我是如何解决我的问题的。 正如sehe所说,问题确实是违反了ODR。我一直在寻找解决这个问题的方法很长一段时间,我找到了一个 - 在带有标志 ASIO_DISABLE_VISIBILITY 的共享库中使用 asio(参见 here)。 ASIO_DISABLE_VISIBILITY 标志隐藏了 ASIO 符号的可见性,这允许在同一个应用程序中使用两种不同的 ASIO 配置(我的情况需要)。