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

时间:2011-03-04 02:39:09

标签: c++ windows multithreading winapi boost

我的代码中很少出现问题,其中触发了断言,涉及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中),然后在lock()中调用boost::detail::basic_recursive_mutex_impl,调用{ {1}} lock()
  • 的方法
  • 在Boost 1.46中,断言(boost::detail::basic_timed_mutex)位于basic_timed_mutex.hpp的第78行,它调用win32 :: WaitForSingleObject:

    BOOST_VERIFY
  • 当Boost.Thread代码等待获取互斥锁上的锁(使用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); 的代码路径)时,没有其他线程持有互斥锁(至少在断言时)发生,并可以在调试器中检查)。这很奇怪,因为它应该能够获得锁定,而不必等待另一个线程放弃控制。
  • 事情看起来很奇怪,检查互斥锁的成员。这些是所有本地和成员变量的值(除非另有说明,否则每次发生时它们都是相同的):
    • WaitForSingleObject - 0xdddddddddddddddddddddddddddddddddddddddddddddddddddddddddd。 - 每次崩溃都是一样的。
    • sem - false
    • lock_acquired - 0xdddddddddddddddddd
    • old_count - 看似有效,并且它的地址与持有它的对象(其中this是一个方法的对象)相匹配。它似乎没有被删除或以任何方式搞乱。
    • handle_write - 一个负整数,我见过的范围介于-570000000和-580000000之间。
    • this->active_count - 0xdddddddddddddddddd

我很遗憾无法看到this->event电话的结果。 API函数上的MSDN entry表示四种可能的返回类型,在这种情况下其中两种是不可能的。由于使用无效事件句柄(WaitForSingleObject = WaitForSingleObject)调用sem,因此我假设它返回0xdddddddddddddddd并且GetLastError将指示已提供无效句柄。< / p>

所以实际问题似乎是0xFFFFFFFF的{​​{1}}方法正在返回get_event()。但是,basic_timed_mutex 0xddddddddddddddddCreateEvent最终使用)告诉我它返回事件的有效句柄或get_event()

同样,这可能是我能提供的问题的最佳描述,因为它不能在此特定应用程序之外可靠地再现。我希望有人能够了解导致这种情况的原因!

1 个答案:

答案 0 :(得分:3)

我想要对您的问题给出一个精确的答案是非常困难的,但似乎您有一个堆损坏问题,您是否尝试过使用正常的pageheap启用AppVerifier? 如果然后将调试器附加到进程并且存在堆损坏,那么当遇到损坏的堆块时,它肯定会中断,您甚至可以查看分配代码的callstack。

编辑:如果使用WinDbg你也可以在WaitForSingleObject(或任何其他函数)上放置条件断点,只有在调用失败时才会中断,然后检查最后一个错误,例如: bp kernel32 !WaitForSingleObject“gu; .if(eax == 0){g}” - &gt;这将告诉调试器在断点处i)运行到函数结束(gu)和ii)检查返回值(存储在EAX寄存器中)并继续执行(g)如果一切正常。如果返回错误,您可以使用!gle 扩展命令检查GetLastError()的值。