win32 :: WaitForSingleObject期间在Windows上Boost.Thread声明/崩溃

在我的代码中有一个很less发生的问题,其中一个断言被触发,涉及到Boost.Thread库。 我不能用一个独立的例子来重现这个问题,我也不知道是什么原因造成的,所以很难提供一个样例。 我希望任何熟悉boost.thread的内部人员都可以提供帮助。

这是我所知道的:

  • boost::lock_guard<boost::recursive_mutex> (或者unique_lock和普通非recursion互斥体的变体)被声明时,就会出现这个问题。
  • 它发生在Boost.Asio的处理函数中。 在堆栈上的线程是io_service::run ,一堆胶水来调用Asiocallback函数,其次是我的callback函数(由async_write调用触发)。 该函数的第一行是导致问题的lock_guard<>的声明。
  • this里面的我的function是有效的,并没有被删除或类似的东西。 debugging器显示它指向有效的数据。 被locking在我的handle_write函数中的互斥handle_write还可以防止删除处理函数使用的内存。
  • 这工作正常,我会说万分之九九九九倍,重的multithreading使用情况正在进行。 如果我将应用程序使用的线程数调低到只处理Asio run()调用的一个线程和主UI线程,则问题会以相同的频率出现。
  • 我的代码的第一行调用互斥锁的lock()方法(在boost::unique_lock<>的ctor中),然后在boost::detail::basic_recursive_mutex_impl中调用lock() ,它调用lock()方法boost::detail::basic_timed_mutex
  • 在Boost 1.46中,assertion( 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代码path)的锁时,没有其他线程持有互斥锁(至less在断言发生的时候,并且可以在debugging器)。 这很奇怪,因为它应该能够获得锁而不必等待另一个线程放弃控制权。
  • 事情看起来很奇怪,检查互斥体的成员。 这些是所有本地和成员variables的值(除非另有说明,每次发生时都是相同的):
    • sem0xdddddddddddddddd – 在每次崩溃时总是相同的。
    • lock_acquiredfalse
    • old_count0xdddddddddddddddd
    • this – 看起来是有效的,它的地址匹配持有它的对象( handle_write是一个方法的对象)。 它似乎没有以任何方式被删除或混淆。
    • this->active_count – 一个负整数,我见过的范围一直在-570000000和-580000000之间。
    • this->event0xdddddddddddddddd

我很遗憾不能看到WaitForSingleObject调用的结果。 API函数中的MSDN条目指示了四种可能的返回types,其中两种在这种情况下是不可能的。 由于WaitForSingleObject被一个无效的事件句柄( sem = 0xdddddddddddddddd0xdddddddddddddddd ,我认为它返回0xFFFFFFFF和GetLastError将表明一个无效的句柄已经提供。

所以实际的问题似乎是, get_event()方法返回0xdddddddddddddddd 。 但是, CreateEvent的MSDN条目 ( get_event()最终使用)告诉我,它返回一个有效的事件句柄或NULL

再次,这可能是我可以提供的问题的最好的描述,因为在这个特定的应用之外它不可靠地重现。 我希望有人有什么可能导致这个问题的想法!

我想这将是非常困难的给你一个精确的答案你的问题,但似乎你有一个堆腐败问题,你有没有试图使用正常pageheap启用AppVerifier? 如果您随后将调试程序附加到进程中,并且发生堆损坏,那么当遇到损坏的堆块时,它可能会中断,甚至可以查看分配代码的调用堆栈。

编辑:如果使用WinDbg,你也可以在WaitForSingleObject(或任何其他函数)上打破条件断点,只有在调用失败的情况下,才能检查最后的错误,例如: bp kernel32!WaitForSingleObject“gu; .if(eax == 0) {g}“ – >这将告诉调试器在断点i)运行到函数(gu)的末尾,ii)检查返回值(存储在EAX寄存器中)并继续执行(g)精细。 如果返回错误,您可以使用!gle extension命令检查GetLastError()的值。