c++ - win32::WaitForSingleObject 期间 Windows 上的 Boost.Thread 断言/崩溃

标签 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 中的互斥锁函数还防止删除处理函数使用的内存。
  • 这工作得很好,我想说一万次中有 9,999 次,并且大量使用多线程。如果我将应用程序使用的线程数减少到仅一个处理 Asio run() 调用的线程和一个主 UI 线程,那么问题出现的频率相同。
  • 我的代码的第一行调用 lock()互斥锁的方法(在 boost::unique_lock<> 的 ctor 中),然后调用 lock()boost::detail::basic_recursive_mutex_impl ,它调用 lock()方法boost::detail::basic_timed_mutex .
  • 在 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 -
    • old_count - 0xdddddddddddddddd
    • this - 看起来是有效的,并且它的地址与持有它的对象所具有的地址相匹配(handle_write 是该对象的一个​​方法)。它似乎没有被删除或以任何方式弄乱。
    • this->active_count - 负整数,我见过的范围在 -570000000 到 -580000000 之间。
    • this->event - 0xdddddddddddddddd

很遗憾,我无法看到 WaitForSingleObject 的结果称呼。 MSDN entry API 函数上指示四种可能的返回类型,其中两种在本场景中是不可能的。自 WaitForSingleObject正在使用无效的事件句柄( sem = 0xdddddddddddddddd )调用,我假设它返回 0xFFFFFFFF GetLastError 将指示提供了无效句柄。

所以,实际的问题似乎是 get_event()方法basic_timed_mutex正在返回0xdddddddddddddddd 。然而,MSDN entry对于 CreateEvent (get_event() 最终使用)告诉我它返回事件的有效句柄,或 NULL

同样,这可能是我能提供的对问题的最佳描述,因为它在该特定应用程序之外无法可靠地重现。我希望有人知道可能导致此问题的原因!

最佳答案

我想很难对您的问题给出准确的答案,但您似乎遇到了堆损坏问题,您是否尝试过在启用正常页面堆的情况下使用AppVerifier? 如果您随后将调试器附加到进程并出现堆损坏,那么当遇到损坏的堆 block 时,它有望中断,您甚至可以查看分配代码的调用堆栈。

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

关于c++ - win32::WaitForSingleObject 期间 Windows 上的 Boost.Thread 断言/崩溃,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/5189068/

相关文章:

windows - 为多个gradle任务创建临时目录

windows - 更好的 Windows 命令行 shell

c++ - 在 For 循环中使用 {} 且不使用 {} 的 If 语句

c++ - 为树莓派交叉编译 QT 应用程序 - 无法打开共享对象文件

c++ - 使用 `static_cast` 向下转换空指针(单继承或多继承)

python - 如何使用win环境变量 "pathlib"保存文件?

c++ - 连续的互斥锁阻塞

python - threading.Timer如何避免Python中的递归?

c++ - 双CPU内存分配性能

C++ fstream覆盖文件