在win32 :: WaitForSingleObject期间,Windows上的Boost.Thread断言/崩溃

我的代码中很少出现问题,其中触发了断言,涉及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
函数中的互斥锁也可以防止删除处理函数使用的内存。 这样可以正常工作,我会说10,000个中有9,999次,并且正在进行大量的多线程使用。如果我将应用程序使用的线程数减少到只处理一个处理Asio run()调用的线程和一个主UI线程,则问题会以相同的频率发生。 我的代码的第一行调用互斥锁的
lock()
方法(在
boost::unique_lock<>
的ctor中),然后在
boost::detail::basic_recursive_mutex_impl
中调用
lock()
,它调用
boost::detail::basic_timed_mutex
lock()
方法。 在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
- 0xddddddddddddddddd - 每次崩溃都是一样的。
lock_acquired
- 假。
old_count
- 0xdddddddddddddddddd。
this
- 看起来是有效的,并且它的地址与持有它的对象(其中的对象
handle_write
是一种方法)相匹配。它似乎没有被删除或以任何方式搞乱。
this->active_count
- 负整数,我见过的范围介于-570000000和-580000000之间。
this->event
- 0xdddddddddddddddddd。 遗憾的是,我无法看到
WaitForSingleObject
电话的结果。 API函数上的MSDN条目指示四种可能的返回类型,在这种情况下其中两种是不可能的。由于使用无效事件句柄(
sem
=
0xdddddddddddddddd
)调用
WaitForSingleObject
,我假设它返回
0xFFFFFFFF
而GetLastError表示已提供无效句柄。 所以实际问题似乎是
basic_timed_mutex
get_event()
方法正在返回
0xdddddddddddddddd
。但是,
CreateEvent
(最终使用的MS26ѭ)的MSDN条目告诉我它返回一个事件的有效句柄,或者
NULL
。 同样,这可能是我能提供的问题的最佳描述,因为它在该特定应用之外不可靠地再现。我希望有人对可能造成这种情况的想法有所了解!     
已邀请:
我想要对你的问题给出一个精确的答案是非常困难的,但似乎你有一个堆损坏问题,你是否尝试过使用正常的pageheap启用AppVerifier? 如果您随后将一个调试器附加到进程并且有一个堆损坏,那么当遇到损坏的堆块时,它肯定会中断,您甚至可以查看分配代码的callstack。 编辑:如果使用WinDbg你也可以在WaitForSingleObject(或任何其他函数)上放置一个条件断点,只有在调用失败时才会中断,然后检查最后一个错误,例如:bp kernel32!WaitForSingleObject“gu; .if(eax == 0) {g}“ - >这将告诉调试器在断点处i)运行到函数结束(gu)和ii)检查返回值(存储在EAX寄存器中)并继续执行(g)如果一切都是精细。如果返回错误,您可以使用!gle extension命令检查GetLastError()的值。     

要回复问题请先登录注册