-1

我试图弄清楚这个问题。

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

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

基本上,应用程序非常大,大多数 DLL 被加载以完成一些工作,然后它们被卸载。对于包含色阶代码的 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为如此懒惰和聪明找到解决方法。
4

1 回答 1

0

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

因此,基本上,当您使用上述解决方法(多次调用带有虚拟参数的信号)时,会发生什么,它的作用是将从代码创建的对象替换为_shared_stateboost代码创建main.dll的另一个_shared_state对象。该对象在内部维护指向引用计数器(类型派生自)的指针。boosttools.dllboost::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时会发生。

于 2015-02-25T11:42:58.127 回答