使用boost :: signals2和卸载DLL时访问冲突

时间:2015-02-24 18:26:14

标签: c++ qt boost dll signals2

我试图找出这个问题。

假设您有一个使用boost::signals2进行对象间通信的代码。让我们称他们为#34; colorscales"。这些颜色标记的代码通常与使用它们的代码位于同一个DLL中。我们称之为main.dll

但有时来自其他DLL的代码需要使用这些对象,这就是问题开始的地方。

基本上,应用程序非常大,并且大多数DLL都被加载以执行某些工作,然后卸载它们。对于包含colorscales代码的DLL,情况并非如此,它在应用程序正常运行时期间被卸载。

因此,当加载其中一个DLL(让我们称之为tools.dll)并运行一些代码时,它可能想要使用这些色阶对象并与它们通信,因此我连接到这些对象提供的信号。

问题在于boost非常懒惰而且非常聪明,当你disconnect()插槽时,它实际上并不会删除connection以及与之相关的内容(像boost::bind对象等。它只是设置了一个标志,这个connection现在已经断开连接并在以后清理它(实际上,当你连接新的插槽时,它会清理其中的两个对象,当你从1.57版本调用信号时,它会清除其中的一个)。你可能已经看到了它的发展方向。

因此,当您不需要更多工具时,您可以断开这些信号,然后应用程序卸载tools.dll

然后在稍后阶段,一些代码从main.dll执行,这会导致调用一个色阶信号。 boost::signals2去调用它,但在它尝试清理一个断开连接的插槽之前。这是发生访问冲突的地方,因为内部连接有一个shared_state对象或类似的东西,它试图以线程安全的方式清理自己。但它面临的问题是,它试图调用的代码已经不存在,因为DLL已被卸载,因此抛出了Access Violation异常。

我试图通过在卸载DLL之前调用带有一些虚拟参数的信号以及通过连接然后断开更多插槽来解决这个问题(这个是一个愚蠢的想法,因为它没有解决问题,但只是将它增加了一些预定义的时间(比根据槽数多2或3倍)。

它有用,或者我是这么认为的,因为它现在不会立即崩溃,而是在下次加载相同的tools.dll时崩溃。我仍然需要弄清楚它崩溃的地点和原因,但它位于boost内的其他地方。

所以,我想问一下,我有哪些修理方法? 我的想法是

  • 实现我自己的连接,以更简单的方式工作
  • 提供更简单的通信方式,例如回调,例如
  • 找到boost变得如此懒惰和聪明的解决方法。

1 个答案:

答案 0 :(得分:0)

好吧,似乎我在修复后找到了崩溃的原因。

因此,基本上,当您使用上述解决方法(多次使用伪参数调用信号)时会发生什么,它的作用是替换从_shared_state代码创建的boost对象来自main.dll的另一个_shared_state对象,来自boost的{​​{1}}代码。此对象维护指向内部的引用计数器(从tools.dll派生的类型)的指针。

然后boost::detail::sp_counter_base卸载并保留对象,但其虚拟表指向不再存在的代码。让我们看一下参考计数器的虚拟表,以了解发生了什么。

tools.dll

正如您所看到的,所有这些方法都与参考计数器的处理相关联,因此在您尝试第二次执行相同的操作之前不会出现问题。因此,断开所有信号以试图摆脱 [0] 0x000007fed8a42fe5 tools.dll!boost::detail::sp_counted_impl_p<...>::`vector deleting destructor'(unsigned int) [1] 0x000007fed8a4181b tools.dll!boost::detail::sp_counted_impl_p<...>::dispose(void) [2] 0x000007fed8a4458e tools.dll!boost::detail::sp_counted_base::destroy(void) [3] 0x000007fed8a43c42 SegyTools.dll!boost::detail::sp_counted_impl_p<...>::get_deleter(class type_info const &) [4] 0x000007fed8a42da6 tools.dll!boost::detail::sp_counted_impl_p<...>::get_untyped_deleter(void) 中的所有代码的技巧无法按预期工作,并且下次您尝试执行此操作时,tools.dll会发生。