我的代码中有一个罕见的问题,其中触发了涉及 Boost.Thread 库的断言。我无法使用独立的示例重现此问题,而且我真的不知道是什么原因导致的,因此很难提供示例案例。我希望任何熟悉 boost.thread 内部结构的人都能提供帮助。
这是我所知道的:
- 当
boost::lock_guard<boost::recursive_mutex>
(或 unique_lock 和普通非递归互斥体的变体)被声明。 - 它发生在 Boost.Asio 的处理函数中。堆栈上是执行
io_service::run
操作的线程。 ,一堆调用 Asio 回调函数的粘合剂,后面是我的回调函数(由 async_write 调用触发)。该函数的第一行是lock_guard<>
的声明这是导致问题的原因。 -
this
我的函数内部是有效的,并且尚未被删除或类似的内容。调试器显示它指向有效数据。被锁定在我的handle_write
中的互斥锁函数还防止删除处理函数使用的内存。 - 这工作得很好,我想说一万次中有 9,999 次,并且大量使用多线程。如果我将应用程序使用的线程数减少到仅一个处理 Asio run() 调用的线程和一个主 UI 线程,那么问题出现的频率相同。
- 我的代码的第一行调用
lock()
互斥锁的方法(在boost::unique_lock<>
的 ctor 中),然后调用lock()
在boost::detail::basic_recursive_mutex_impl
,它调用lock()
方法boost::detail::basic_timed_mutex
. 在 Boost 1.46 中,断言 (
BOOST_VERIFY
) 位于 basic_timed_mutex.hpp 第 78 行,它调用 win32::WaitForSingleObject:do { BOOST_VERIFY(win32::WaitForSingleObject( sem,::boost::detail::win32::infinite)==0); clear_waiting_and_try_lock(old_count); lock_acquired=!(old_count&lock_flag_value); } while(!lock_acquired);
- 当 Boost.Thread 代码等待获取互斥锁时(使用
WaitForSingleObject
的代码路径)所做的事情,没有其他线程持有互斥锁(至少在断言发生时,并可以在调试器中进行检查)。这很奇怪,因为它应该能够获得锁,而不必等待另一个线程放弃控制。 - 检查互斥体的成员时,事情看起来很奇怪。这些是所有局部变量和成员变量的值(除非另有说明,否则每次发生这种情况时它们都是相同的):
-
sem
- 0xdddddddddddddddd - 每次崩溃时,这始终是相同的。 -
lock_acquired
- 假。 -
old_count
- 0xdddddddddddddddd。 -
this
- 看起来是有效的,并且它的地址与持有它的对象所具有的地址相匹配(handle_write
是该对象的一个方法)。它似乎没有被删除或以任何方式弄乱。 -
this->active_count
- 负整数,我见过的范围在 -570000000 到 -580000000 之间。 -
this->event
- 0xdddddddddddddddd。
-
很遗憾,我无法看到 WaitForSingleObject
的结果称呼。 MSDN entry API 函数上指示四种可能的返回类型,其中两种在本场景中是不可能的。自 WaitForSingleObject
正在使用无效的事件句柄( sem
= 0xdddddddddddddddd
)调用,我假设它返回 0xFFFFFFFF
GetLastError 将指示提供了无效句柄。
所以,实际的问题似乎是 get_event()
方法basic_timed_mutex
正在返回0xdddddddddddddddd
。然而,MSDN entry对于 CreateEvent
(get_event()
最终使用)告诉我它返回事件的有效句柄,或 NULL
。
同样,这可能是我能提供的对问题的最佳描述,因为它在该特定应用程序之外无法可靠地重现。我希望有人知道可能导致此问题的原因!
最佳答案
我想很难对您的问题给出准确的答案,但您似乎遇到了堆损坏问题,您是否尝试过在启用正常页面堆的情况下使用AppVerifier? 如果您随后将调试器附加到进程并出现堆损坏,那么当遇到损坏的堆 block 时,它有望中断,您甚至可以查看分配代码的调用堆栈。
编辑:如果使用 WinDbg,您还可以在 WaitForSingleObject(或任何其他函数)上放置一个条件断点,仅当调用失败时才会中断,然后检查最后一个错误,例如:bp kernel32 !WaitForSingleObject "gu; .if(eax == 0) {g}" -> 这将告诉调试器在断点处 i) 运行到函数末尾 (gu) 并 ii) 检查返回值(存储在 EAX 寄存器中)并继续执行 (g) 如果一切正常。如果返回错误,您可以使用 !gle 扩展命令检查 GetLastError() 的值。
关于c++ - win32::WaitForSingleObject 期间 Windows 上的 Boost.Thread 断言/崩溃,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/5189068/