Windows :: 스레드 생성 함수와 예제 // CreateThread _beginthreadex
/*
* made by so_Sal
*/
스레드 (혹은 쓰레드, Thread) 에 대해서 잘 모르신다면
링크로~! ^-^ :: LINK_
/*
* CreateThread()
* ExitThread()
* GetExitCodeThread()
* _beginthreadex()
* ResumeThread();
* _endthreadex()
* -------------
*/
Windows에서 쓰레드를 생성하는 가장 기본적인 함수는
CreateThread 입니다.
HANDLE CreateThread(
1. LPSECURITY_ATTRIBUTES lpThreadAttributes,
2. SIZE_T dwStackSize,
3. LPTHREAD_START_ROUTINE lpStartAddress,
4. LPVOID lpParameter,
5. DWORD dwCreationFlags,
6. LPDWORD lpThreadId );
1. LPSECURITY_ATTRIBUTES lpThreadAttributes,
SECURITY_ATTRIBUTES 구조체는,
생성하는 핸들에 대해 보안속성을
2. SIZE_T dwStackSize //dw는 DWORD겠죠 ㅎㅎ
쓰래드는 고유의 스택을 가지고 있습니다. 스택 크기를 지정합니다.
0 (또는 NULL) :: Default 값으로 1mb가 적용됩니다.
3. LPTHREAD_START_ROUTINE lpStartAddress
쓰레드가 작동할 함수의 이름을 넣으시면 됩니다.
typedef DWORD (WINAPI *PTHREAD_START_ROUTINE)
(LPVOID lpThreadParameter);
typedef PTHREAD_START_ROUTINE LPTHREAD_START_ROUTINE;
함수 예)
DWORD WINAPI ThreadEx(LPVOID lpParameter){
return 0;
}
4. LPVOID lpParameter
함수의 인자로 넘어가는것과 같습니다.
더블 포인터도 가능합니다.
5. DWORD dwCreationFlags, //Flag 입니다.
CREATE_SUSPEND
:: suspend count 1로 설정 ( 스레드 priority control 관련글 참고 링크 :: LINK_ )
:: suspend count가 0이 되기 전까지는, 스레드는 동작하지 않습니다.
이 인자를 넣을 시에, 원하는 시기에 스레드를 시작할 수 있습니다.
DWORD ResumeThread(HANDLE hThread) :: Suspend Count 1 감소
DWORD SuspendThread(HANDLE hThread) :: Suspend Count 1 증가
STACK_SIZE_PARAM_IS_A_RESERVATION
:: Reserve stack size를 변경하려면 위 플레그를 추가 한 후
스레드 생성 함수들의 매개변수 dwStackSize파라미터를 사용한다.
아래는 CreationFlag이지만, 프로세스에서만 쓰인다.
CREATE_NEW_CONSOLE
DEBUG_PROCESS | DEBUG_ONLY_THIS_PROCESS
6. LPDWORD lpThreadId
생성시에 이 변수로 쓰레드ID가 전달됩니다.
필요 없다면 NULL.
return :: HANDLE.
CreateThread 함수의 리턴값은, 스레드를 가리키는 핸들
스레드는 독립된 스택을 할당받기 때문에 메모리를 차지하게 됩니다.
메모리가 허용하는 만큼 스레드 생성이 가능합니다.
void ExitThread(DWORD dwExitCode)
이 함수는 실행중인 스레드를 종료하고자 할 때 호출하는 함수입니다.
(사실 return과 다를 바 없다.)
return으로 종료되는 스레드나, 이 함수로 종료되는 스레드나
모두 아래에 설명할 GetExitCodeThread 함수로 리턴값 (혹은 ExitCode값)을
반환받을 수 있다.
스레드의 리턴값을 가져오는 함수입니다.
BOOL GetExitCodeThread(
1 HANDLE hThread,
2 LPDWORD lpExitCode );
1. HANDLE :: 정상적인 리턴으로 종료된 스레드를 가리키는 핸들값
2. lpExitCode :: DWORD 자료형 변수의 주소값을 넣어주면
스레드의 리턴값 DWORD값을 반환
다중 프로세스의 경우에, GetExitCodeProcess() 함수 또한,
위와 같이 사용할 수 있습니다. (자료형, 매개변수가 같습니다.)
#include<process.h> 헤더파일이 필요합니다.
uintptr_t _beginthreadex(
void *_Security,
unsigned int _StackSize,
unsigned int(*_StartAdrdress)(void *),
void *_ArgList,
unsigned int _InitFlag,
unsigned int *_ThrdAddr );
매개변수는 CreateThread와 일치합니다.
매개변수들의 자료형을 더욱 범용적으로 쓰기 위해서
자료형의 형태가 수정되었습니다.
CreateThread() 와 위 함수의 가장 큰 차이점은,
독립적인 메모리 블록 할당에 있습니다.
_beginthreadex() 함수 역시 내부적으로 CreateThread()를 호출합니다.
종료호출로 ExitThread() 대신, 아래 함수로 대신합니다.
(ExitThread() 함수를 쓰는 이유는 독립적인 "메모리 블록 할당" 에 있습니다.)
void _endthreadex(unsigned retval);
ExitThread() 함수와 역시 동일합니다. 하지만,
_endthreadex() 함수를 쓰는 이유는,
CreateThread()와 _beginthreadex() 함수간의 차이에 있습니다.
_beginthread() 함수에서는 독립적인 메모리 블록 할당을 한다고 하였습니다.
따라서 스레드 종료시에, 할당한 메모리를 반환해야만 합니다.
이 역할을 하는 함수가 _endthreadex() 입니다.
======================== CreateThread() 사용 함수 예제 ========================
/*
* CraeteThread()함수를 이용하여 스레드를 생성한 후
* 각각의 스레드에 매개변수로 1~10을 넘깁니다.
* 스레드는 매개변수로 받은 숫자 1~10을 전역변수 STotal 변수에 +=으로 더하고,
* 매개변수값을 리턴합니다.
* 메인루틴에서는 스레드가 리턴한값을 차례대로 GetExitCodeThread() 함수를 통해
* 반환하여 모두 더하고, 전역변수와 리턴값의 합을 출력합니다.
* ExitThread() 함수는 사용하지 않고, return을 이용했습니다.
* ExitThread() 함수를 이용해 직접 짜보시면 이해에 더욱 도움이 될 것 같습니다.
*/
#include<stdio.h>
#include<windows.h>
#include<tchar.h>
#define MAX_THREADS (10)
DWORD STotal = 0;
DWORD WINAPI ThreadProc(LPVOID lpParam);
// 생성될 Thread가 수행할 내용이 담긴 함수
int _tmain(int argc,TCHAR *argv[]){
DWORD cntOfThread=0;
DWORD dwThreadID[MAX_THREADS];
HANDLE hThread[MAX_THREADS];
DWORD Total =0;
DWORD Result=0;
while(1){
if(cntOfThread == MAX_THREADS){
_tprintf( _T("MAXIMUM THREAD NUMBER : %d\n") ,cntOfThread);
break;
}
hThread[cntOfThread] =
CreateThread(
NULL,0,ThreadProc,
(LPVOID)cntOfThread,
0,
&dwThreadID[cntOfThread]);
cntOfThread++;
} //while문을 이용하여 10개의 스레드 생성
Sleep(1000);
// 스레드가 자신의 할일을 모두 수행하고, 리턴값을 남기고 사라짐
// 리턴값을 이용하여 Total 계산
for(DWORD i=0; i<cntOfThread; i++){
GetExitCodeThread(hThread[i],&Result);
Total += Result;
CloseHandle(hThread[i]);
}
_tprintf( _T(" Total :: %d \n"), Total); //스레드의 리턴값으로 얻은 Total
_tprintf( _T("STotal :: %d \n"), STotal); //스레드가 전역변수에 접근하여 계산된 값
return 0;
}
DWORD WINAPI ThreadProc(LPVOID lpParam){
STotal += (DWORD)lpParam; // 전역변수도 접근 가능
return (DWORD)lpParam; // 리턴값 전달 가능
}
======================== _beginthreadex() 사용 함수 예제 ========================
/*
* 위 CreateThread() 예제와
* 같은 일을 수행합니다.
*/
#include<stdio.h>
#include<windows.h>
#include<tchar.h>
#include<process.h> //beginthreadex() 함수 사용시 필요 헤더파일
#define MAX_THREADS (10)
DWORD STotal = 0;
unsigned int WINAPI ThreadProc(LPVOID lpParam);
// 생성될 Thread가 수행할 내용이 담긴 함수.
// CreateThread와는 다르게 unsigned int 자료형을 사용합니다.
int _tmain(int argc,TCHAR *argv[]){
DWORD cntOfThread=0;
DWORD dwThreadID[MAX_THREADS];
HANDLE hThread[MAX_THREADS];
DWORD Total =0;
DWORD Result=0;
while(1){
if(cntOfThread == MAX_THREADS){
_tprintf( _T("MAXIMUM THREAD NUMBER : %d\n") ,cntOfThread);
break;
}
hThread[cntOfThread] =
(HANDLE) _beginthreadex( //HANDLE로의 형변환이 필요합니다.
NULL,0,ThreadProc,
(LPVOID)cntOfThread,
0,
(unsigned *)&dwThreadID[cntOfThread]);
cntOfThread++;
} //while문을 이용하여 10개의 스레드 생성
Sleep(1000);
// 스레드가 자신의 할일을 모두 수행하고, 리턴값을 남기고 사라짐
// 리턴값을 이용하여 Total 계산
for(DWORD i=0; i<cntOfThread; i++){
GetExitCodeThread(hThread[i],&Result);
Total += Result;
CloseHandle(hThread[i]);
}
_tprintf( _T(" Total :: %d \n"), Total); //스레드의 리턴값으로 얻은 Total
_tprintf( _T("STotal :: %d \n"), STotal); //스레드가 전역변수에 접근하여 계산된 값
return 0;
}
unsigned int WINAPI ThreadProc(LPVOID lpParam){ //unsigned int 자료형
STotal += (DWORD)lpParam; // 전역변수도 접근 가능
return (DWORD)lpParam; // 리턴값 전달 가능
}