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()続行されることがわかりました。クリティカル セクション コードに到達すると、クリティカル セクションが無効になるため、その場で終了します。これは、スレッド内のキャンセル イベントをチェックする方法です (私のアプリケーションでは、実行中に 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()はやく戻らなくちゃ?thread_func()また、 if threadTerminatedisではクリーンアップは行われませんTRUE

これがIMOの最も奇妙な部分です。を削除するWaitForMultipleObjects()と、私のコードは問題なく動作します! 内部のクリーンアップを含め、すべてのクリーンアップが行われthread_func()ます。誰かがこれを理解するのを手伝ってくれますか?

threadTerminated今のところ一点だけチェックしていることに注意してください。後で他の重要なポイントで確認します。何が起こっているのかを理解しているかどうかを確認するためだけにこれを行っています。

再度、感謝します!あなたの答えは非常に役に立ちます。

4

2 に答える 2

4

プロセスが終了すると、OSは割り当てられたすべてのメモリを解放するため、割り当てられたプロセスを呼び出さfreeなくてfileNameも問題は発生しません。

とにかく、私は次のようにコードを変更します:

  1. スレッドを終了する必要があるかどうかを示すフラグを定義します。bool terminated;
  2. プロセスが終了しようとしているときに、に設定terminated、スレッドが終了するのtrueを待ちます。
  3. スレッド関数で、terminated重要なポイントをチェックします(たとえば、すべてのループの条件チェックで)。の場合、スレッドによって実行されたすべての処理terminatedtrue停止し(たとえば、ループを停止)、リソースを解放し(たとえば、スレッドによって割り当てられたメモリを解放し)、戻ります。
  4. スレッドが終了した後(つまり、スレッド関数が戻った後)、プロセスは残りのすべてのリソースを解放し(たとえば、プロセスによって割り当てられたメモリを解放したり、クリティカルセクションを削除したりするなど)、終了できます。

このようにして、スレッドが終了する前にクリティカルセクションを削除することを回避でき、割り当てられたすべてのリソースを解放できます。

于 2013-02-13T14:50:56.370 に答える
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);
  ...
}

編集 :

スレッドを作成および削除すると、多くのオーバーヘッド コードが作成され、プログラムの速度が低下する可能性があることに注意してください。作業量がオーバーヘッドと比較して重要なワーカー スレッドでない限り、プログラムの存続期間中はスレッドをアクティブにしておくことを検討してください。

于 2013-02-13T15:21:46.153 に答える