簡體   English   中英

線程分配內存,主進程死掉,會發生什么?

[英]Thread allocates memory, main process dies, what happens?

我目前正在檢查一些內存泄漏的代碼,這種可能性讓我感到震驚。 基本上我正在做的偽代碼如下,

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)有一個Cancel按鈕。 當用戶點擊該按鈕時,我調用DLL的清理功能,這恰好會破壞我的關鍵部分。

我發現如果用戶在執行thread_func()期間單擊Cancel,則thread_func()將繼續執行。 當它到達臨界區代碼時,關鍵部分無效,所以我就在那里退出。 這就是我在線程中檢查取消事件的方法(因為我的應用程序中的其他任何東西都不能在執行thread_func()期間調用DLL的清理)。

當我發現臨界區無效時,我無法在thread_func()釋放fileName 我的猜測是因為thread_func()進程退出后, thread_func()失去了對fileName訪問權限。 我猜對了嗎? 我的主要問題是,如果我在這種情況下不釋放fileName ,我是否存在內存泄漏的風險?

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

謝謝!

編輯:

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

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()無限期掛起,我的GUI變得沒有響應。 WaitForMultipleObjects()不應該快速返回嗎? 此外,如果threadTerminatedTRUE ,則thread_func()thread_func()發生任何清理。

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

請注意,我現在只在一點檢查threadTerminated 我稍后會在其他重點檢查。 我這樣做只是為了看看我是否理解發生了什么。

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

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

無論如何,我會通過以下方式更改代碼:

  1. 定義一個標志,指示線程是否應該終止: bool terminated;
  2. 當進程即將終止時,將terminated設置為true ,並等待線程終止
  3. 在線程函數中,檢查在重要點terminated (例如,在每個循環的條件檢查中)。 如果terminatedtrue ,則停止線程完成的所有操作(例如,停止循環),釋放資源(例如,線程分配的空閑內存),然后返回。
  4. 線程終止后(即,在返回線程函數之后),進程可以釋放每個剩余資源(例如,進程分配的空閑內存,刪除關鍵部分等)並退出。

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

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

設計這個的正確方法是這樣的:

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);
  ...
}

編輯:

請記住,創建和刪除線程會產生大量開銷代碼,並可能會降低程序速度。 除非它們是工作線程,與開銷相比工作量很大,所以考慮在程序的整個生命周期中保持線程處於活動狀態但是處於睡眠狀態。

暫無
暫無

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

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