2013-02-13 112 views
3

我目前正在檢查一些代碼,我有內存泄漏,這種可能性讓我感到震驚。基本上,我在做什麼的僞代碼如下所示,線程分配內存,主進程死亡,會發生什麼?

void thread_func() 
{ 
    char *fileName = malloc(someSize); 
    /* Do something with fileName and other things */ 
    /* Enter a critical section */ 
    modify some global variables 
    /*Exit critical section */ 
    free(fileName); 
    return; 
} 

此函數駐留在DLL中。關鍵部分和其他東西由同樣駐留在同一個DLL中的函數初始化。

現在,我的主進程(這是一個GUI)有一個取消按鈕。當用戶點擊該按鈕時,我會調用DLL的清理函數,這個函數恰好會破壞我的關鍵部分。

我發現如果用戶在執行thread_func()期間點擊取消,thread_func()將繼續執行。當它到達關鍵部分代碼時,關鍵部分是無效的,所以我在那裏退出。這是我如何檢查線程內的取消事件(因爲在執行thread_func()期間,我的應用程序中沒有其他任何東西可以調用DLL的清除)。

我不能免費fileNamethread_func()當我發現臨界區無效。我的猜測是因爲thread_func()由於主進程退出而失去對fileName的訪問。我的猜測是對的嗎?我的主要問題是,如果我在這種情況下沒有免費使用fileName,我是否會冒內存泄漏的風險?

我已經搜索了很多相關信息,到目前爲止還沒有找到任何東西。如果有人能指出我正確的方向/回答我的問題,我會非常高興。

謝謝!

編輯:

,我決定做根據科爾的建議的一些初步測試(見下面的回答)。我注意到了一些我無法理解的奇怪東西。現在,我的代碼如下:

void thread_func() 
{ 
    char *fileName = malloc(someSize); 
    /* Do something with fileName and other things */ 

    if(threadTerminated) 
    { 
     /* Cleanup */ 
     return; 
    } 

    /* Enter a critical section */ 
    modify some global variables 
    /*Exit critical section */ 
    free(fileName); 
    return; 
} 

而在我的GUI,我OnCancel事件處理程序是這樣的:

void OnCancel() 
{ 
    threadTerminated = TRUE; 
    WaitForMultipleObjects(noOfRunningThreads, threadHandles, TRUE, INFINITE); 

    /* Other cleanup code */ 
} 

我注意到,WaitForMultipleObjects()無限期掛起我的圖形用戶界面變得無法響應。 WaitForMultipleObjects()不應該快速返回?另外,如果threadTerminatedTRUE,則在thread_func()中沒有發生清理。

這是IMO最奇怪的部分。當我刪除WaitForMultipleObjects()時,我的代碼工作得很好!所有的清理工作都會發生,包括thread_func()內的清理。有人能幫我理解嗎?

請注意,我現在只在一個點上檢查threadTerminated。稍後我會在其他重要的部分檢查它。我只是爲了看看我是否瞭解發生了什麼。

再次感謝!你的回答非常有幫助。

+0

有不同類型的內存泄漏,在不增加它往往是更不方便的不是一個實際的問題,因爲程序終止反正和泄漏是不隨時間增長泄漏的情況。 – 2013-02-13 15:12:14

+0

@claptrap,好點!但是我想清除任何我發現的內存泄漏情況。 – 2013-02-13 16:06:37

+0

如果僅在進程退出時調用DLL的清理函數,則不要打擾銷燬關鍵部分。該建築正在拆除,所以你不需要掃地。如果您需要處理DLL被卸載但進程將繼續進行的情況,那麼您需要根據現有答案將清理與線程同步。請記住,即使在沒有關鍵部分的情況下,當線程仍在運行代碼時,也無法安全地卸載DLL。 – 2013-02-13 22:07:15

回答

4

當進程終止時,操作系統將釋放所有已分配的內存,因此不會在分配的fileName上調用free不會導致任何問題。

無論如何,我會改變代碼的方式如下:

  1. 定義指示線程是否應該終止的標誌:bool terminated;
  2. 當進程即將結束,設置terminatedtrue,和wait for the thread to terminate
  3. 在線程函數中,請檢查terminated的重要位置(例如,在每個循環的條件檢查中)。如果terminatedtrue,則停止線程完成的所有操作(例如,停止循環),釋放資源(例如線程分配的空閒內存)並返回。
  4. 線程終止後(即線程函數返回後),進程可以釋放每個剩餘的資源(例如,進程分配的空閒內存,刪除關鍵部分等)並退出。

這樣可以避免在線程終止前刪除關鍵部分,並且您可以釋放每個分配的資源。

+1

我不會推薦一個布爾。改爲使用事件,以便線程可以休眠而不會產生無意義的CPU負載。看到我的答案。 – Lundin 2013-02-13 15:22:45

+0

@Lundin我不確定一個事件對於這個目的更好。我的意思是沒有必要在這面旗幟上等待。線程完成它的工作,並且在決策點,它檢查標誌以決定它是否可以繼續執行或者應該以優雅的方式終止。 (Delphi的設計者使用相同的邏輯:TThread類具有終止屬性,這是一個布爾值。) – kol 2013-02-13 15:49:59

+0

感謝您的回答!這絕對是對我的問題可能的解決方案。 @倫丁,你爲什麼不推薦一個布爾?只是好奇。 – 2013-02-13 15:51:35

1
  • 你的線程可能應該有某種形式的循環纔有意義。
  • 使用線程時,您需要發明一些方法以安全,可預測的方式正常終止它們。
  • 關鍵部分是鈍的,用線程可以等待的互斥對象替換它們。

設計,這將是這樣的正確的方法:

HANDLE h_event_killthread = CreateEvent(...); 
HANDLE h_mutex = CreateMutex(...); 

... 

void thread_func() 
{ 
    const HANDLE h_array [] = 
    { 
    h_event_killthread, 
    h_mutex 
    }; 

    ... // malloc etc 

    bool time_to_die = false; 

    while(!time_to_die) 
    { 
    DWORD wait_result; 
    wait_result = WaitForMultipleObjects(2,   // wait for 2 handles 
             h_array, // in this array 
             FALSE,  // wait for any handle 
             INFINITE); // wait forever 

    if(wait_result == WAIT_OBJECT_0) // h_event_killthread 
    { 
     time_to_die = true; 
    } 
    else if(wait_result == (WAIT_OBJECT_0+1)) //h_mutex 
    { 
     // we have the mutex 
     // modify globals here 
     ReleaseMutex(h_mutex); 

     // do any other work that needs to be done, if meaningful 
    } 
    } 

    cleanup(); 
} 


// and then in the GUI: 

void cancel_button() 
{ 
    ... 
    SetEvent(h_event_killthread); 
    WaitForSingleObject(the_thread, INFINITE); 
    ... 
} 

編輯:

請有記住,創建和刪除線程創造了很多的開銷代碼和可能減慢程序。除非它們是工作線程,工作量相對於開銷而言是重要的,否則應考慮在線程整個生命週期中保持線程活着但睡着。

+1

我強烈建議[此](http://www.flounder。com/badprogram.htm)優秀的閱讀。 – Lundin 2013-02-13 15:30:44

+0

感謝您的回答!這絕對看起來像我所擁有的更好的設計。什麼是WAIT_OBJECT_0?另一個問題,你爲什麼說關鍵部分是鈍的?此外,該鏈接看起來很有趣。非常感謝你! – 2013-02-13 15:55:16

+0

哦,不用關心'WAIT_OBJECT_0',用google搜索了一下。另一件事,目前我的應用程序中只有一小部分是多線程的,它要求所有線程同時啓動(不是我的決定),否則我可能會考慮暫停線程的建議。 – 2013-02-13 16:05:05