2011-03-04 91 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