스레드와 C런타임 라이브러리
스레드를 만들때 Win32 API 함수인 CreateThread()를 사용하였다.
하지만 CreateThread()함수를 쓸 때에는 조심하여야한다.
대부분의 프로그램은 C런타임 라이브러리에 상당한 의존을 한다.
C런타임 라이브러리는 각각의 스레드가 라이브러리를 사용할 때 적절하게 초기화되어야 하는
특징을 가지고 있는 데 그 이유는
1. Win32 API는 운영체제에 의해 구현되었다.
하지만 C런타임 라이브러리는 컴파일러 제작사에 의해서 구현되었기 때문에
서로 불일치하게 되면 스레드가 생성될 때 C런타임 라이브러리를 코드의 밖으로 빠지게 한다.
2. C런타임 라이브러리의 어떤 함수들은 함수 사이에서 상태를 유지하고 있다.
이런 경우를 대비해서 런타임 라이브러리는 각 스레드에 대해서 C런타임 라이브러리를 초기화하는 함수인 _beginthread와 _beginthreadex를 제공한다.
ExitThread를 사용하면 endthread를 호출할 필요가 없다.
올바른 정리 프로시저는 스레드 시작 프로시저가 리턴될 때 런타임 라이브러리에 의해서 자동으로 호출되기 때문에
C런타임 라이브러리는 CreateThread 호출에 의해서 스레드를 사용하는 경우를 검출할 수 있다.
_beginthread의 호출에 의해서 이루어지는 대부분의 초기화 작업을 동적으로 수행할 수 있다.
그러나 시그널이나 예외 처리, 메모리 leak과 같은 경우에 대처할 수 없다.
_beginthread함수의 원형
unsinged long _beginthread( void (__cdecl *start _adress) (void *), unsigned stack_size, void *arglist);
start _adress
- 새 스레드가 수행을 시작하면 호출할 사용자 함수의 주소
stack_size
- 새 스레드의 스택 크기(바이트). 이 매개변수가 0이면 스택 크기는 현재 프로세스의 주 스레드와 같게된다.
- 시스템은 스택의 상한값을 1MB로 제한하여서 함수가 제한없이 재귀적으로 호출하는 것을 방지하며, 4기가바이트의 주소 공간이 모두 사용되는 것을 막는다.
arlist
- start_adress가 가리키는 스레드 시작 프로시저에 전달되는 임의의 인자
_beginthreadex의 원형
unsinged long _beginthreadex ( void * security, unsinged stack_size,
unsinged (stdcall *start_proc) (void *), void *arg, unsinged initflag, unsigned * thraddr);
security
- 새로 생성된 스레드의 보안과 속성을 지정하는 SECURITY_ATTRIBUTE의 구조체 포인터
- NULL이면 스레드는 디폴트 보안 속성으로 생성된다.
- 현재 프로세스의 자식 프로세스는 스레드 핸들을 상속받을 수 없다.
stack_size
- 새로운 스레드에 할당할 스택 크기(바이트) 이 값이 0이면 스택 크기는 현재 프로세스의
주 스레드의 스택 크기와 같다.
- 시스템은 크기의 상한을 1MB로 정해서 함수가 제한없이 재귀적으로 동작하는 것을 방지한다.
start_proc
- 새로운 스레드가 수행을 시작할 때 호출할 사용자 함수의 주소.
arg
- 사용자 정의 32비트 값
- Start_proc이 지정한 루틴으로서 새로 생성된 스레드의 lpThreadParameter로 값이 넘겨진다.
initflag
- 스레드 생성을 조절하는 추가적인 매개변수
- 이 값이 CREATE_SUSPENDED값이면 스레드는 대기 카운트 1의 값을 갖고 대기상태로 생성
된다. ResumeThread 함수의 호출에 의해서 수행을 시작하게 된다.
이 값이 0이면 스레드는 즉시 수행을 시작하게 된다.
thraddr
- 스레드 식별자를 받을 DWORD 값의 포인터이다.
** C런타임 라이브러리를 사용하는 프로그램에서 ExitThread 함수를 사용하면 안된다.
ExitThread 함수를 호출하는 경우에 스레드가 런타임 환경을 지원하기 위해서 할당된
자원을 정리할 기회를 얻을 수 없다.
스레드가 시작 함수에서 리턴하지 않고, 종료하는 경우엔 ExitThread 호출하는 대신
_endthreadex 호출해야 한다.