2013-02-13 3 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을 해제하지 않으면 메모리 누수 위험이 있습니까?

관련 정보를 꽤 많이 검색했지만 지금까지 아무 것도 찾지 못했습니다. 나는 누군가가 올바른 방향으로 나를 가르키고/나의 질문에 대답 할 수 있다면 매우 행복 할 것이다.

감사합니다.

편집 : 나는 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 인 경우 클린업이 발생하지 않습니다.

가장 이상한 부분은 IMO입니다. WaitForMultipleObjects()을 제거하면 제 코드가 제대로 작동합니다! 청소는 thread_func() 안에 포함하여 모든 청소가 이루어집니다. 누군가가 나를 이해하도록 도와 줄 수 있습니까?

지금 당장은 threadTerminated을 확인하고 있습니다. 나는 나중에 다른 중요한 요점에서 그것을 점검 할 것이다. 무슨 일이 일어나는지 이해했는지 확인하기 위해이 작업을하고 있습니다.

다시 한번 감사드립니다! 귀하의 답변은 매우 유용합니다.

+0

다른 유형의 메모리 누수가 있습니다. 누출이 커지지 않는 경우 프로그램이 어쨌든 종료되고 누수가 시간이 지남에 따라 커지지 않기 때문에 실제로 문제보다 불편합니다. –

+0

@claptrap, 좋은 지적입니다! 그러나 내가 찾은 메모리 누수 시나리오를 지우고 싶습니다. –

+0

프로세스가 종료 될 때 DLL의 정리 기능이 호출되는 경우 단순히 중요한 섹션을 파괴하지 마십시오. 건물이 철거되어 바닥을 청소할 필요가 없습니다! DLL이 언로드되지만 프로세스가 계속 진행될 경우를 처리해야하는 경우 기존 응답마다 스레드와 정리를 동기화해야합니다. 중요한 섹션이 없어도 스레드가 코드를 실행하고있는 동안 안전하게 DLL을 언로드 할 수는 없습니다. –

답변

4

프로세스가 종료되면 OS는 할당 된 모든 메모리를 비울 것이므로 에 할당 된 free을 호출해도 아무런 문제가 발생하지 않습니다.

  1. 스레드가 종료할지 여부를 나타내는 플래그를 정의합니다 :

    어쨌든, 나는 코드를 다음과 같이 변경됩니다 프로세스를 종료하려고 할 때 bool terminated;trueterminated을 설정

  2. 을하고, wait for the thread to terminate.
  3. 스레드 기능에서 중요 지점 (예 : 모든 루프의 상태 확인)에서 terminated을 확인하십시오. terminatedtrue이면 스레드가 수행 한 모든 작업 (예 : 루프 중지)을 중지하고 리소스 (예 : 스레드에서 할당 한 여유 메모리)를 해제 한 다음 반환하십시오.
  4. 스레드가 종료 된 후 (즉, 스레드 함수가 반환 된 후) 프로세스는 남아있는 모든 리소스 (예 : 프로세스에서 할당 한 여유 메모리, 중요한 섹션 삭제 등)를 해제하고 종료 할 수 있습니다.

이렇게하면 스레드가 종료되기 전에 중요한 섹션을 삭제하지 않고 할당 된 모든 리소스를 확보 할 수 있습니다.

+1

나는 bool을 추천하지 않는다. 스레드를 대신 무의미한 CPU로드가 발생하지 않고 절전 모드로 전환 할 수 있도록 이벤트를 사용하십시오. 내 대답을 보라. – Lundin

+0

@ Lundin 나는이 목적을 위해 이벤트가 더 나은지 확신하지 못합니다. 나는이 깃발을 기다릴 필요가 없다는 것을 의미합니다. 스레드는 작업을 수행하고 결정 지점에서 플래그를 검사하여 진행 여부를 결정하거나 정상적으로 종료되어야하는지 여부를 결정합니다. 델파이의 디자이너들은 동일한 로직을 사용했습니다 : TThread 클래스는 부울 (Boolean) 인 Terminated 속성을가집니다. – kol

+0

답변 해 주셔서 감사합니다! 이것은 확실히 내 문제에 대한 가능한 해결책처럼 보입니다. @ Lundin, 왜 당신은 bool을 추천하지 않습니까? 그냥 궁금해서. –

1
  • 스레드는 의미있는 루프 형태 여야합니다.
  • 스레드를 사용하여 작업 할 때 안전하고 예측 가능한 방식으로 스레드를 정상적으로 종료 할 수있는 방법을 고안해야합니다.
  • 중요 섹션은 무딘 경우 스레드가 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); 
    ... 
} 

편집 :

만들고 스레드를 삭제하면 오버 헤드가 많은 코드를 작성하고 수 있음을 염두에두고하세요 프로그램 속도를 늦추십시오. 오버 헤드에 비해 작업량이 중요한 작업자 스레드가 아니라면 프로그램의 전체 수명 동안 스레드를 활성 상태로 유지하면서 잠들게하는 것을 고려하십시오.

+1

나는 [this] (http : //www.flounder.com/badprogram.htm) 우수한 독서. – Lundin

+0

답변 해 주셔서 감사합니다. 이것은 확실히 내가 가지고있는 것보다 훨씬 나은 디자인처럼 보입니다. 하지만 'WAIT_OBJECT_0'은 무엇입니까? 또 다른 질문은 왜 비판적 섹션이 무딘가하는 것입니까? 또한,이 링크는 꽤 흥미 롭습니다. 고마워요! –

+0

오 WAIT_OBJECT_0에 대해 신경 쓰지 마세요, googled. 또 다른 것은 현재 응용 프로그램의 일부분 만 멀티 스레드이며, 모든 스레드가 동시에 시작되어야합니다 (내 결정이 아님). 그렇지 않으면 일시 중단 스레드 제안을 고려했을 수 있습니다. –

관련 문제