윈도우즈에서 스레드를 생성하는 API는 CreateThread(), _beginthread(), _beginthreadex() 이렇게 3개의 함수가 존재합니다.
CreateThread()와 _beginthread(), _beginthreadex()의 차이점은 다음과 같습니다.
함수 원형을 보고 알 수 있는 파라메터에 의한 차이점은 다음과 같습니다.
왜 그럴까요? _beginthread()로 생성된 스레드 핸들은 스레드 함수의 실행이 종료될 때 _beginthread() 내부에서 CloseHandle()을 호출하기 때문에 프로그래머가 GetExitCodeThread()를 사용할 수 있는 시점에서는 이미 소멸된 핸들이 되기 때문입니다.
_beginthreadex()는 위와 같은 문제를 해결하기 위해 스레드가 종료될때 내부적으로 CloseHandle()를 호출하지 않고 사용자가 명시적으로 해제하도록 변경되었습니다.
결과적으로 내용을 정리하면 다음과 같습니다.
CreateThread()와 _beginthread(), _beginthreadex()의 차이점은 다음과 같습니다.
- CreateThread()는 스레드를 생성하는 기능만 담당한다.
- _beginthread(), _beginthreadex()는 내부적으로 CreateThread() 를 사용하여 스레드를 생성하고 C Runtime library에서 내부적으로 필요로 하는 메모리 영역을 초기화 해주는 역할을 하게 됩니다. 초기화 되는 메모리 영역은 각 스레드 마다 따로 관리되게 됩니다.
그렇다면 _beginthread(), _beginthreadex()의 차이는 무엇일까요? 의외로 이 차이에 대해서 대답을 명쾌하게 해주는 분이 많지가 않습니다. 이제부터 그 차이를 설명해 보도록 하겠습니다.
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()를 사용할 수 없습니다.
BOOL WINAPI GetExitCodeThread(
HANDLE hThread,
LPDWORD lpExitCode
);
|
왜 그럴까요? _beginthread()로 생성된 스레드 핸들은 스레드 함수의 실행이 종료될 때 _beginthread() 내부에서 CloseHandle()을 호출하기 때문에 프로그래머가 GetExitCodeThread()를 사용할 수 있는 시점에서는 이미 소멸된 핸들이 되기 때문입니다.
_beginthreadex()는 위와 같은 문제를 해결하기 위해 스레드가 종료될때 내부적으로 CloseHandle()를 호출하지 않고 사용자가 명시적으로 해제하도록 변경되었습니다.
결과적으로 내용을 정리하면 다음과 같습니다.
- _beginthread()로 생성된 스레드 핸들은 스레드 종료시에 CloseHandle()이 내부적으로 호출되어 신경쓸 필요가 없지만 스레드 함수 완료 후 스레드 핸들을 이용한 어떠한 API 함수도 실행 시킬 수 없습니다.
- _beginthreadex()로 생성된 스레드 핸들은 스레드가 실행완료된 후 내부적으로 CloseHandle()을 실행시키지 않기 때문에 스레드 핸들을 이용한 API 함수를 실행할 수 있지만 사용자가 명시적으로 CloseHandle()을 호출해 주어야 합니다. 만약 CloseHandle()을 해주지 않으면 핸들이 계속 쌓이게 되는 Resource leak이 생기게 됩니다.
'Development > C/C++' 카테고리의 다른 글
[Sleep함수] (0) | 2011.11.29 |
---|---|
[thread에서 _beginthreadex의 void *arglist로 스레드에 여러 인수 넘겨주는 방법] (0) | 2011.11.23 |
[select FD_SET FD_Zero FD_Clr FD_IsSet] (0) | 2011.11.22 |
[_beginthreadex 형변환문제] (0) | 2011.11.22 |
[thread 함수와 예제] (0) | 2011.11.22 |