2015-02-24 86 views
-1

我试图找出这个问题。使用boost :: signals2和卸载DLL时访问冲突

假设您的代码使用boost::signals2进行对象之间的通信。让我们称他们为“色彩”。这些colorscales的代码通常位于与使用它们的代码相同的DLL中。我们称之为main.dll

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

基本上,应用程序是相当大的,大多数的DLL被加载做一些工作,然后他们被卸载。对于包含colorscales代码的DLL,情况并非如此,它在应用程序正常运行时期间被卸载。因此,当其中一个DLL被加载(我们称之为tools.dll)并且一些代码运行时,它可能想要使用这些色彩对象并与它们通信,因此我连接到这些对象提供的信号。

的问题是,boost是非常懒惰,所有的聪明,当你disconnect()插槽,它实际上并没有抹去connection和与它(如boost::bind对象,例如)相关的东西。它只是设置一个标志,这个connection现在已断开连接,并在稍后清理它(实际上,当您连接新插槽时清除其中的2个对象,当您调用1.57版本时调用其中的1个对象)。你可能已经看到了这将会到来。

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

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

我试图通过在卸载DLL之前调用带有一些虚拟参数的信号来解决这个问题,并且通过连接然后断开更多的插槽来解决这个问题(这是一个愚蠢的想法,因为它不能解决问题,它)一些预定义的时间量(比所有时隙多2或3倍)。

它的工作,或我认为是这样,因为它现在不会立即崩溃,而是在下次加载相同的tools.dll时崩溃。我仍然需要弄清楚它在哪里以及为什么会崩溃,但它在boost之内的其他地方。

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

  • 实现我自己的连接,在一个更简单的方式
  • 提供了一个更简单的方法来沟通一样,回调的作品,例如
  • 找到一个解决方法boost如此懒惰和聪明。
+0

你有没有想过不通过DLL传递提升对象?重新发明whell(子弹一)是一个坏主意。找到解决方法将帮助您了解更多信息,但可能需要无限期的时间。我会去更简单的方法。 – UmNyobe 2015-02-24 18:57:14

+0

那么,这是问题的全部。这是因为它没有解决方法就无法工作。问题是:我应该选择哪种解决方法 – Spo1ler 2015-02-24 23:10:11

回答

0

嗯,似乎我已经找到修复后崩溃的原因。

所以,基本上,会发生什么,当你使用上面(与虚拟参数多次呼叫信号)中描述的解决方法,它的作用是,它取代了从boost代码由另一个_shared_state对象创建从main.dll_shared_state对象创建自的代码boost。该对象维护指向参考计数器(类型派生自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中的所有代码的技巧并不像预期的那样工作,并且下次尝试执行该技巧时,会发生Access Violation

+0

很大,你正在取得进展。你有没有找到你的解决方法? – UmNyobe 2015-02-25 12:50:56

+0

我认为,如果我将这种“诡计”的代码移动到擦除断开的插槽到'main.dll',它将实际上工作,由于上述原因。 – Spo1ler 2015-02-25 13:05:42

+0

或者我可以只使用其他语言工具进行通信(就像在项目中使用的Qt一样),因为'main.dll'之外的代码不需要全部的信号信息。 – Spo1ler 2015-02-25 13:07:28