2011-03-04 92 views
2

我的代码中有一个很少发生的问题,其中触发了一个断言,涉及Boost.Thread库。我无法使用独立示例重现此问题,但我不知道是什么造成了这一问题,因此很难提供示例。我希望任何熟悉boost.thread的内部人员都可以提供帮助。win32中的Boost.Thread声明/ Windows崩溃:: WaitForSingleObject

这是我所知道的:

  • 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<>的构造函数),然后调用在boost::detail::basic_recursive_mutex_impl,它调用的boost::detail::basic_timed_mutexlock()方法lock()
  • 在升压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指示了四种可能的返回类型,其中两种在这种情况下是不可能的。由于WaitForSingleObject正在使用无效事件句柄(sem = 0xdddddddddddddddd)进行调用,因此我假定它返回0xFFFFFFFF,并且GetLastError表示提供了无效句柄。

因此,实际问题似乎是basic_timed_mutexget_event()方法正在返回0xdddddddddddddddd。但(get_event()最终使用)的MSDN entry告诉我,它返回一个有效的事件句柄或NULL

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

回答

3

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

编辑:如果使用WinDbg的你也可以把WaitForSingleObject的一个条件断点(或任何其他功能)打破只在调用失败,然后检查最后一个错误,如:BP KERNEL32 WaitForSingleObject的“合谷。 if(eax == 0){g}“ - >这会告诉调试器在断点i)运行到函数结尾(gu)并且ii)检查返回值(存储在EAX寄存器中)和继续执行(g)如果一切正常。如果返回错误,您可以使用扩展命令检查GetLastError()的值。

+0

堆腐败是我的猜测,这就是它最终成为 - 一个界限溢出。在预感上,我将少数几个使用char []的地方之一切换到了bounds-checked boost :: array,并找到了问题。我不知道AppVerifier,谢谢!然而,我无法让它与我的应用程序一起工作。 – 2011-03-05 22:33:20