안전한 쓰레드 종료 코드 직접 만들기

주싱·2021년 5월 5일
0

Software Engineering

목록 보기
3/12
post-thumbnail

아름답게(?) 작성되지 않은 레거시 프로그램을 유지보수하다 보면 쓰레드 종료를 안전하게 하지 않은 코드 패턴을 종종 발견한다. 이로 인해 생긴 교묘한 버그로 고생한 경험이 있어서 어떻게 쓰레드를 종료하는 것이 안전한 것인지 정리해 두려고 한다.

안전한 쓰레드 종료 조건

쓰레드를 안전하게 종료해 주기 위해서는 쓰레드 코드와 쓰레드를 종료해 주는 코드 양쪽 모두 잘 작성되어야 한다.

Thread Code

쓰레드 코드는 아래의 3가지 조건을 항상 만족하도록 작성되어야 한다.

  • 쓰레드는 어딘가에서 무한히 Blocking 되어 있는 코드가 없어야 한다.
  • 쓰레드는 종료 신호를 주기적으로 체크하고 종료 신호 수신 시 종료될 수 있어야 한다.
  • 쓰레드 종료 시, 할당한 자원을 정상적으로 해제해야 한다.
DWORD __stdcall ThreadFunc(LPVOID param) {
    
    // 파일 열기
    fpPB = fopen("Temp.dat", "ab");

    while (bStop == FALSE) {
        ...
        fwrite(TempData, size, 1, fpPB);
        ...
    }

    // 파일 닫기
    fclose(fpPB);
}

Thread Terminator

Thread Terminator 는 Thread 에게 실행 종료를 알리고(플래그 또는 이벤트 객체를 통해), 실제로 Thread가 종료될 때 까지 기다리도록 한다.

void Some()
{
    // 쓰레드 생성
    handle = CreateThread ... 
    if (handle == NULL) { ... } 

    // do something... 

    // 쓰레드 종료 신호 전달    
    bStop = TRUE; 

    // 실제 쓰레드 종료 대기 
    WaitForSingleObject(handle, INFINITE); 
    
    // 쓰레드 핸들 닫기 
    if (handle != NULL) {
        CloseHandle(handle); 
        handle = NULL;
    }

}

비정상적인 쓰레드 종료

흔히 잘못 작성하는 쓰레드 종료 코드를 Worst 부터 정리해 보면 크게 두가지 유형이 있는 것 같다.

강제 종료 : TerminateThread()

Worst 케이스는 TerminateThread()를 통해 강제로 아무 시점에나 쓰레드를 종료하는 방법이다.

MSDN에서 TerminateThread() 함수 설명을 보면 엄청난 경고를 하고 있다.

MSDN

TerminateThread is used to cause a thread to exit. When this occurs, the target thread has no chance to execute any user-mode code. DLLs attached to the thread are not notified that the thread is terminating. The system frees the thread's initial stack.
...
TerminateThread is a dangerous function that should only be used in the most extreme cases. You should call TerminateThread only if you know exactly what the target thread is doing, and you control all of the code that the target thread could possibly be running at the time of the termination. For example, TerminateThread can result in the following problems:

쓰레드 종료 기다리지 않아

두번 째 좋지 않은 방법은 Thread 종료를 위해 단지 종료하라는 신호만 주고 쓰레드 종료를 실제 기다리지 않는 코드이다. 이와 같은 경우 여러 환경에 따라 미묘한 버그를 만들어 개발자를 많이 힘들게 하는 경우가 있는 것 같다.

정리

쓰레드는 반드시 예외없이 안전하게 종료되어야 한다. 만약 이 규칙을 지키지 않는다면 매우 간헐적으로 발생하는 수 많은 버그들에 고통 받게 될 가능성이 크다.

👇
DEBUG : API를 호출해도 파일이 삭제되지 않아요?

profile
소프트웨어 엔지니어, 일상

0개의 댓글