首页 文章

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

提问于
浏览
2

我的代码中很少出现问题,其中触发了断言,涉及Boost.Thread库 . 我无法使用一个独立的示例重现此问题,我真的不知道是什么导致它,所以很难提供一个示例案例 . 我希望任何熟悉boost.thread内部的人都可以提供帮助 .

这就是我所知道的:

  • 声明 boost::lock_guard<boost::recursive_mutex> (或unique_lock和普通非递归互斥锁的变体)时会出现问题 .

  • 它发生在Boost.Asio的处理函数中 . 在堆栈上是执行 io_service::run 的线程,一堆调用Asio回调函数的 Binders ,然后是我的回调函数(由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_mutexlock() 方法 .

  • 在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 - false .

  • old_count - 0xdddddddddddddddd .

  • this - 看似有效,并且它的地址与持有它的对象(其中 handle_write 是方法的对象)匹配 . 它似乎没有被删除或以任何方式搞乱 .

  • this->active_count - 一个负整数,我见过的范围介于-570000000和-580000000之间 .

  • this->event - 0xdddddddddddddddd .

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

所以实际问题似乎是 basic_timed_mutexget_event() 方法正在返回 0xdddddddddddddddd . 但是, CreateEventget_event() 最终使用)告诉我它返回一个事件的有效句柄,或 NULL .

同样,这可能是我能提供的问题的最佳描述,因为它在该特定应用之外不可靠地再现 . 我希望有人对可能造成这种情况的想法有所了解!

1 回答

  • 3

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

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

相关问题