2009-11-16 70 views
1

我正在調試這個數據庫項目。它爲更高級別的應用程序提供對SQLite的訪問。它被設計爲異步運行,也就是說,它有像ExecuteRequestAsync()和IsRequestReady()這樣的方法。當調用ExecuteRequestAsync時,它會派生一個boost :: thread來執行該作業並立即返回該函數。當高層應用程序決定不再需要運行請求的結果時,它可能會調用DumpRequest()來取消它。由於很難正常取消數據庫請求,DumpRequest的實現只是維護一個「清理監視器線程」,等待「已完成的請求」並將其刪除。所有boost ::線程通過升壓:: shared_ptr的管理,如:boost :: thread導致小事件句柄泄漏?

boost::shared_ptr<boost::thread> my_thread = new boost::thread(boost::bind(&DBCon::RunRequest, &this_dbcon)); 

而且當它不再需要(被取消):

vector<boost::shared_ptr<boost::thread> > threads_tobe_removed; 
// some iteration 
threads_tobe_removed[i].get()->join(); 
threads_tobe_removed.erase(threads_tobe_removed.begin()+i); 

我創造了這個單元測試項目來測試執行和轉儲請求的機制。它運行請求並隨機取消正在運行的請求,並重複數千遍。機制證明是可以的。一切按預期工作。

但是,通過通過sysinternal的Process Explorer觀察單元測試項目,發現存在句柄泄漏問題。每經過500次,手柄數量增加1,永不退回。這是增加的「事件」類型句柄。文件和線程句柄沒有增加(當然,隨着線程的產生,句柄的數量也在增加,但每隔一百次就會有一次Sleep(10000)調用,以等待它們被清理,以便可以觀察到句柄計數)。

我一直沒有管理自己的事件處理。它們是在創建線程時由boost :: thread創建的。我只保證優雅地關閉線程,我不知道事件是用來幹什麼的。

我想知道是否有人遇到過類似的問題?什麼可能是這個泄漏的原因? Process Explorer中的這個數字是否可靠足以將其稱爲句柄泄漏?有什麼方法可以追蹤和修復它嗎?

我在Windows Vista上使用Visual C++靜態鏈接boost 1.40。

+0

產生100個請求並立即轉儲它們通常在Intel CoreDuo E6600上花費約3秒鐘。打開的句柄的峯值數量約爲300(包括事件,線程,文件等)。當測試進入睡眠狀態時,打開的手柄編號逐漸降低到65左右。每隔500小時通過一次,將導致「結束」編號從65增加到66,然後是67. 這實際上是一次每50,000次執行。這非常奇怪和令人沮喪。 – 2009-11-16 12:20:22

+0

「打開的句柄數逐漸減少」,因爲清理監視器線程正在收集它們。 – 2009-11-16 12:23:40

回答

1

是否可以訪問threads_tobe_removed線程安全?如果不是,那麼當一個線程通過調用DumpRequest向該向量添加一個線程時,可能會出現競態條件,而清理監視器線程會從該向量中刪除一個線程。因此,boost::thread對象可能會首先加入線程而被銷燬,這會使線程在沒有關聯對象的情況下運行,這可能會解釋泄漏。

+0

當然,它使用互斥鎖來鎖定。同步在這裏不是問題。必要時鎖定完成。否則,它不會導致線程處理泄漏,而不是事件處理? 奇怪的是,泄漏只發生在0.2%的請求中。 – 2009-11-16 12:18:01

+2

我認爲0.2%的泄漏比任何其他數字更可能發生泄漏。提升撰稿人是有才華的編碼員。這不會錯過簡單的100%泄漏。這很可能是由於微妙的競爭條件導致的泄漏,這種情況很少發生。然而,默認情況下,我認爲boost是正確的,如果你真的認爲你已經發現了一些東西,將它分解成最少量的代碼來重現問題並打到boost郵件列表。 – 2009-11-16 16:44:01