Windows API에서는 CreateThread() 함수를 사용하여 스레드를 생성합니다. Pthreads와 마찬가지로 이 함수에는 보안 정보, 스택 크기, 스레드 플래그와 같은 속성들이 전달됩니다. 아래 예제 프로그램에서는 이러한 속성들에 기본값을 사용합니다. (기본값으로는 스레드가 일시 중단 상태로 설정되지 않으며, 대신 CPU 스케줄러에 의해 실행될 수 있는 상태가 됩니다.)
합계를 계산하는 스레드가 생성된 후에는 Sum 값이 해당 스레드에 의해 설정되기 때문에, 부모 스레드는 Sum 값을 출력하기 전에 반드시 자식 스레드의 작업이 끝날 때까지 기다려야 합니다. Pthreads 프로그램에서는 pthread_join() 문을 사용하여 부모 스레드가 합계 계산 스레드를 기다리게 했습니다. Windows API에서는 이와 동일한 동작을 WaitForSingleObject() 함수로 수행할 수 있으며, 이 함수는 합계 계산 스레드가 종료될 때까지 생성한 스레드를 블록(대기) 상태로 만듭니다.
여러 스레드 대기하기: WaitForMultipleObjects()
여러 개의 스레드가 모두 완료될 때까지 기다려야 하는 경우에는 WaitForMultipleObjects() 함수를 사용합니다. 이 함수에는 다음과 같은 네 개의 매개변수가 전달됩니다.
- 대기할 객체의 개수
- 객체 배열을 가리키는 포인터
- 모든 객체가 신호(signaled) 상태인지 여부를 나타내는 플래그
- 타임아웃 시간 (또는 INFINITE)
예를 들어, THandles가 크기 N인 스레드 HANDLE 객체 배열이라면, 부모 스레드는 다음 문장을 통해 모든 자식 스레드의 완료를 기다릴 수 있습니다.
WaitForMultipleObjects(N, THandles, TRUE, INFINITE);
Windows API를 사용하는 멀티스레드 C 프로그램
예제 코드
다음은 Windows API를 활용하여 별도의 스레드에서 0부터 입력받은 정수까지의 합을 계산하는 완전한 C 프로그램입니다.
#include<windows.h>
#include<stdio.h>
DWORD Sum;
/* data is shared by the thread(s) */
/* thread runs in this separate function */
DWORD WINAPI Summation(LPVOID Param){
DWORD Upper = *(DWORD*)Param;
for (DWORD i = 0; i <= Upper; i++)
Sum += i;
return 0;
}
int main(int argc, char *argv[]){
DWORD ThreadId;
HANDLE ThreadHandle;
int Param;
if (argc != 2){
fprintf(stderr,"An integer parameter is required\n");
return -1;
}
Param = atoi(argv[1]);
if (Param < 0){
fprintf(stderr,"An integer >= 0 is required\n");
return -1;
}
/* create the thread */
ThreadHandle = CreateThread( NULL, /* default security attributes */ 0, /* default stack size */
Summation, /* thread function */ &Param, /* parameter to thread function */ 0, /* default creation flags */ &ThreadId);
/* returns the thread identifier */
if (ThreadHandle != NULL){
/* now wait for the thread to finish */ WaitForSingleObject(ThreadHandle,INFINITE);
/* close the thread handle */
CloseHandle(ThreadHandle);
printf("sum = %d\n",Sum);
}
}코드 동작 방식 설명
위 프로그램의 핵심 흐름은 다음과 같습니다.
- 매개변수 검증: main() 함수는 명령줄 인수로 정수 하나를 받으며, 인수가 없거나 음수일 경우 오류 메시지를 출력하고 종료합니다.
- 스레드 생성: CreateThread() 호출 시 보안 속성(NULL), 스택 크기(0, 기본값), 스레드 함수(Summation), 매개변수(&Param), 생성 플래그(0), 스레드 식별자(&ThreadId)를 전달합니다.
- 데이터 공유: 전역 변수 Sum은 부모 스레드와 자식 스레드가 공유하며, Summation() 함수가 0부터 Upper까지의 값을 더해 저장합니다.
- 동기화 및 정리: WaitForSingleObject()로 스레드 종료를 대기한 후, CloseHandle()로 스레드 핸들을 닫고 최종 결과를 출력합니다.