簡體   English   中英

win32::WaitForSingleObject 期間 Windows 上的 Boost.Thread 斷言/崩潰

[英]Boost.Thread Assertion/Crash on Windows during win32::WaitForSingleObject

我的代碼中有一個很少發生的問題,其中觸發了一個斷言,涉及 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<>然后調用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調用的結果。 API 函數上的MSDN 條目指示四種可能的返回類型,其中兩種在這種情況下是不可能的。 由於WaitForSingleObject使用無效的事件句柄 ( sem = 0xdddddddddddddddd ) 被調用,我假設它返回0xFFFFFFFF並且 GetLastError 將表明提供了一個無效的句柄。

所以實際的問題,現在看來,是該get_event()的方法basic_timed_mutex將返回0xdddddddddddddddd 但是, CreateEventMSDN 條目get_event()最終使用)告訴我它返回事件的有效句柄或NULL

同樣,這可能是我可以提供的問題的最佳描述,因為它在此特定應用程序之外無法可靠地重現。 我希望有人對可能導致這種情況的原因有想法!

我想很難對您的問題給出准確的答案,但是您似乎遇到了堆損壞問題,您是否嘗試過在啟用了正常頁堆的情況下使用 AppVerifier? 如果您隨后將調試器附加到進程並發生堆損壞,則它有望在遇到損壞的堆塊時中斷,您甚至可以查看分配代碼的調用堆棧。

編輯:如果使用 WinDbg,您還可以在 WaitForSingleObject(或任何其他函數)上放置一個條件斷點,僅當調用失敗時才中斷,然后檢查最后一個錯誤,例如: bp kernel32!WaitForSingleObject "gu; .if(eax == 0) {g}" -> 這將告訴調試器在斷點處 i) 運行到函數的末尾 (gu) 和 ii) 檢查返回值(存儲在 EAX 寄存器中)並繼續執行 (g) 如果一切正常美好的。 如果返回錯誤,您可以使用!gle擴展命令檢查 GetLastError() 的值。

暫無
暫無

聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM