前言
最近在寫遠程獲取電腦屏幕得時候遇到了多線程中共享同一內存區域,這塊內存區域是new動態申請得。其中發生了一些困惑得問題,貌似是在線程切換過程中delete會無法釋放new得內存區域在此記錄一下。
問題描述
A線程用來new內存並delete(是個循環),B線程用來訪問這塊內存區域(也是個循環)。在A線程new內存后准備delete這塊區域時,有可能正好切換到B線程進行訪問這塊內存區域。然后在切換到A線程后delete沒有釋放掉這塊內存區域。
調試器內分析
-
調試然后先斷到A線程
此時new得共享內存中已經有數據了,准備delete這塊內存
-
接着運行中斷到B線程,然后我們繼續運行會回到A線程delete處並執行完delete。
-
當執行完delete后其指向下一條指令,這時new得數據被delete成功了
-
接着反復運行會發現delete會出現無法清除new的內存得情況
隨之反復運行會發生嚴重的內存泄漏!
問題發生原因
猜測是在頻繁的線程切換使delete發生錯誤。
利用線程同步避免問題
利用互對象進行線程同步,防止在delete的時候切換線程。
A線程中就用如下形式
while(1)
{
WaitForSingleObject(hmutex, INFINITE); //請求互斥對象
new ; //申請內存
ReleaseMutex(hmutex); //釋放互斥對象句柄
Sleep(200); //讓B進程處理
ReleaseMutex(hmutex); //釋放互斥對象句柄
WaitForSingleObject(hmutex, INFINITE); //請求互斥對象
delete ; //釋放內存
}
B線程形式如下
while(1)
{
WaitForSingleObject(hmutex, INFINITE); //請求互斥對象
訪問共享內存
ReleaseMutex(hmutex); //釋放互斥對象句柄
}
(由此還可以看出互斥對象在A進程中剛開始是WaitForSingleObject(hmutex, INFINITE)請求互斥對象會遞增此線程擁有的對象計數,接着ReleaseMutex(hmutex)釋放會遞減此線程擁有的對象計數,但是接着有調用ReleaseMutex(hmutex)釋放會遞減此線程擁有的對象計數,因為此時線程已經不擁有該對象了所以函數返回錯誤:企圖釋放並非呼叫方所擁有的多用戶終端運行程序,但是並不影響我們程序運行。ReleaseMutex最多是線程擁有的對象計數減到0,這樣我們可以實現只有當Sleep(200)的時候B線程有機會訪問共享內存,從而避免B進程在還沒有new內存或者剛delete內存的時候訪問無效的內存產生錯誤。)