Automotive Software

쓰레드 취소 및 뒷정리 (Thread Cancellation and Cleaning up) 본문

포직스 (POSIX)/쓰레드 프로그래밍 고급 (Advanced Threaded Program)

쓰레드 취소 및 뒷정리 (Thread Cancellation and Cleaning up)

AutoSW 2020. 10. 19. 18:18

쓰레드 사용 시 늘 생각해 볼 부분은 바로 쓰레드의 취소(종료)이다. 좀 더 정확히 말하면 종료 후 아래의 경우에 해당하는 쓰레드의 뒷정리일 것이다.

  • 쓰레드에서 동적 자원을 할당하여 사용할 경우, 종료 후 메모리 누수 (Memory Leakage)
  • 뮤텍스 등의 동기화 메커니즘이 사용된 경우, 다른 쓰레드의 데드락 (Deadlock between Threads)
  • 쓰레드가 어떤 상태를 설정하고 그 상태가 다른 쓰레드 또는 메인 쓰레드에서 참조될 경우, 애플리케이션 상에서 상태 회복 불가능 (Unrecoverable state in an application)

1. 쓰레드 취소

포직스 쓰레드에서는 아래 두 가지의 취소 모드를 제공하는데, 이는 쓰레드의 취소 요청을 어떠한 시점에 처리할지를 결정하게 된다.

  • 지연 취소(Deferred cancellation) : 기본값, 시스템상에서 해당 쓰레드의 다음 취소 시점(Cancellation point)까지 대기
    • pthread_cond_wait(), pthread_join() 그리고 pthread_testcancel() 과 같은 함수가 취소 시점을 제공하므로 해당 함수 호출 때까지 대기
    • 시스템 마다 지원하는 취소 시점(Cancellation point)이 상이 하므로 원하는 취소 동작을 수행할 수 있는지 확인 필요
  • 비동기 취소(Asynchronous cancellation) : 취소 요청시 즉시 처리 시도(지연 가능성 있음)
  • int pthread_setcanceltype( int type, int* oldtype )
    • PTHREAD_CANCEL_DEFERRED
    • PTHREAD_CANCEL_ASYNCHRONOUS
    • 예, pthread_setcanceltype(PTHREAD_CANCEL_ASYNCHRONOUS, NULL);

또는 취소 절차를 허용하지 않도록 설정할 수도 있다.

  • int pthread_setcancelstate( int state, int* oldstate )
    • PTHREAD_CANCEL_ENABLE : 기본값, 상기 취소 타입에 따라 취소 절차 허용
    • PTHREAD_CANCEL_DISABLE : 취소 요청을 계류

2. 쓰레드 뒷정리 처리기 (POSIX Cleaning up handler)

  • 보통 쓰레드 함수 시작과 끝에 처리기를 등록하여 사용
  • pthread_cleanup_push (void (routine)(void*), void* arg);
    • 처리기 함수 등록
  • pthread_cleanup_pop (int execute);
    • 처리기 함수 호출
  • 상기 함수들은 실제 함수가 아닌 코드의 일부로써 브레킷({,})을 사용한 매크로로 구현을 하는 경우가 많으므로, 동일 함수 내에서 하나의 쌍으로만 호출되도록 하는 것이 향후 재사용시 호환성을 높임
    • pthread_cleanup_pop()이 동일 함수내에서 호출되지 않을 경우, 아래와 같은 컴파일 에러가 보고됨
    • error: expected declaration or statement at end of input
int count;

void cleanup_func(void *arg)
{
    int *pCount = (int *)arg;
    (*pCount)--;
}

void *thread_func(void *arg)
{
    /* install the cleanup handler first */
    pthread_cleanup_push(cleanup_func, (void *)&count);
    
    count++;
    while(1)
    {
    	/* thread operation */
    }
    
    /* call it once it is cancelled */
    pthread_cleanup_pop(1);
    
    return NULL;
 }