본문 바로가기
IT-개발,DB

[개발/VC++] CreateThread(), _beginthread(), _beginthreadex() 에 관하여

by SB리치퍼슨 2014. 2. 4.

아래 쓰레드 생성함수에 관한 비교가 참 명쾌하게 되어 있습니다.



A Backwards Glance at Knole!
A Backwards Glance at Knole! by antonychammond 저작자 표시비영리동일조건 변경허락



출처 : http://naiades.tistory.com/6

윈도우즈에서 스레드를 생성하는 API는 CreateThread(), _beginthread(), _beginthreadex() 이렇게 3개의 함수가 존재합니다. 

CreateThread()와 _beginthread(), _beginthreadex()의 차이점은 다음과 같습니다.

  • CreateThread()는 스레드를 생성하는 기능만 담당한다.
  • _beginthread(), _beginthreadex()는 내부적으로 CreateThread() 를 사용하여 스레드를 생성하고 C Runtime library에서 내부적으로 필요로 하는 메모리 영역을 초기화 해주는 역할을 하게 됩니다. 초기화 되는 메모리 영역은 각 스레드 마다 따로 관리되게 됩니다.

  • 그렇다면 _beginthread(), _beginthreadex()의 차이는 무엇일까요? 의외로 이 차이에 대해서 대답을 명쾌하게 해주는 분이 많지가 않습니다. 이제부터 그 차이를 설명해 보도록 하겠습니다.
     

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    
      
    uintptr_t _beginthread( 
       void( *start_address )( void * ),
       unsigned stack_size,
       void *arglist 
    );
    
    uintptr_t _beginthreadex( 
       void *security,
       unsigned stack_size,
       unsigned ( *start_address )( void * ),
       void *arglist,
       unsigned initflag,
       unsigned *thrdaddr 
    );
    

    함수 원형을 보고 알 수 있는 파라메터에 의한 차이점은 다음과 같습니다.

    • _beginthreadex()는 security를 이용하여 보안 관련 설정을 할 수 있다.
    • _beginthreadex()는 initflag를 이용하여 스레드의 초기 동작을 정의 할 수 있다.
    • _beginthreadex()는 thrdaddr을 이용하여 thread id를 받을 수 있다.
    • _beginthreadex()는 __stdcall 형식의 함수 포인터를 thread 실행 함수로 받는다.
    • _beginthreadex()는 함수 실행 실패시에 0을 리턴한다. (_beginthread는 -1을 리턴한다.)
    • 여기에 더해서 가장 중요하게 기억해야 할 한가지의 차이점이 더 존재합니다. (이 내용이 글을 쓰는 이유이기도 합니다. ^^)
      _beginthread()는 스레드가 생성되고 스레드 함수의 실행이 종료 되면 스레드의 정리 작업을 해주게 됩니다. 이러한 형태는 편리한 점이 있지만 단점도 존재하게 되는데 바로 스레드의 실행 완료후에 해당 스레드의 정보를 조회 할 수 있는 방법이 없다는 것입니다. 

      예를 들어 스레드의 종료시에 exit 코드가 무엇인지 알기 위해서 GetExitCodeThread()를 사용할 수 있습니다. 이때 첫번째 인자로 스레드의 핸들을 파라메터로 넘겨줘야 되는데 _beginthread()로 생성된 스레드의 핸들은 GetExitCodeThread()를 사용할 수 없습니다. 

      1
      2
      3
      4
      
      BOOL WINAPI GetExitCodeThread(
        HANDLE hThread,
        LPDWORD lpExitCode
      );
      

      왜 그럴까요? _beginthread()로 생성된 스레드 핸들은 스레드 함수의 실행이 종료될 때 _beginthread() 내부에서 CloseHandle()을 호출하기 때문에 프로그래머가 GetExitCodeThread()를 사용할 수 있는 시점에서는 이미 소멸된 핸들이 되기 때문입니다.

      _beginthreadex()는 위와 같은 문제를 해결하기 위해 스레드가 종료될때 내부적으로 CloseHandle()를 호출하지 않고 사용자가 명시적으로 해제하도록 변경되었습니다.

      결과적으로 내용을 정리하면 다음과 같습니다.

      • _beginthread()로 생성된 스레드 핸들은 스레드 종료시에 CloseHandle()이 내부적으로 호출되어 신경쓸 필요가 없지만 스레드 함수 완료 후 스레드 핸들을 이용한 어떠한 API 함수도 실행 시킬 수 없습니다.
      • _beginthreadex()로 생성된 스레드 핸들은 스레드가 실행완료된 후 내부적으로 CloseHandle()을 실행시키지 않기 때문에 스레드 핸들을 이용한 API 함수를 실행할 수 있지만 사용자가 명시적으로 CloseHandle()을 호출해 주어야 합니다. 만약 CloseHandle()을 해주지 않으면 핸들이 계속 쌓이게 되는 Resource leak이 생기게 됩니다.


반응형

댓글