개념
- Creating a Thread
- Consequences of Using Multiple Threads
- Kernel Objects
- The Thread Exit Code
- Exiting a Thread
- Error Handling
- Background Printing
- Summary or conclusion
스레드 생성 방법
CreateThread() 이용 (C++에서는 beginThreadEx() -> 궁극적으로 CreateThread()를 호출함 즉, CreateThread()가 가장 저수준)
스레드를 생성하기 위해서 ChreadThread()이용
여섯개의 알규먼트와 한개의 리턴타입을 가짐
여섯개의 알규먼트중 마지막은(LPDWORD lpThreadId) 리턴벨류라고 보면 됨. 인자로 넘겨주는거는 5개
HANDLE CreateThread(
LPSECURITY_ATTRIBUTES lpThreadAttributes, // Security Descriptor, pointer to security attributes, 보안특성 같은 속성들, 디폴트는 NULL
SIZE_T dwStackSize, // initial thread stack size(default size 1MB), 각 스레드의 고유한 스택의 크기 지정
LPTHREAD_START_ROUTINE lpStartAddress, // thread function, pointer to thread function(start adress), 함수에 대한 포인터
LPVOID lpParameter, // thread argument, argument for new thread, void 포인터 타입의 알규먼트를 전달받음 void 포인터라 LPVOID임
DWORD dwCreationFlags, // thread identifier, creation flags
LPDWORD lpThreadId // thread identifier, pointer to receive thread ID of the new thread(return value), 스레드 아이디
);반환값
성공시 : a handle to the thread
실패시 : FALSE
스레드 닫기
CloseHandle() 이용. 만약 스레드가 실행중이라면 CloseHandle()에 의해 강제적으로 종료되지 않음(레퍼런스 카운트를 하나 감소시킴?)
스레드의 종료코드를 얻어오는 함수
GetExitCodeThread() 스레드 펑션이 정수형의 리턴타입을 가짐. 함수가 리턴을 하면 그 리턴값을 이용하면 될텐데 왜 종료코드를 얻어오는 함수가 필요하냐? ->
스레드 종료
ExitThread()함수 이용, 스레드 내부에서 호출, 이 코드 이후에 오는 코드는 어떠한 코드든 절대 실행되지 않음
VOID ExitThread(
DWORD dwExitCode // exit code for this thread);
반환값은 아무것도 없음
- Busy Waiting
- Performance Monitors
- Waiting for a Thread to Exit
- Signaled Objects
- Waiting for Multiple Objects
- Waiting in a GUI Program
- Summanry
스레드 종료를 기다리는 방법
sleep()함수 사용 또는 GetExitCodeThread() 함수 사용
sleep()의 문제점 - 스레드가 언제 종료될지 모름, 스레드 실행시간보다 더 많은 시간을 대기시간을 줘야함 안정적 실행을 위해서
GetExitCodeThread() 문제점 - 장점:스레드가 종료되는 시점에 바로 알 수 있어 시간적인 낭비가 없으나, 문제점 : 메인스레드에서 이 함수를 계속 호출해 많은 CPU타임을 낭비함
WaitForSingleObject() 이 함수를 호출하는 오브젝트는 슬립상태가 됨, 호출하면 스레드가 종료될때까지 기다림(커널 오브젝트 뭐든 넣을수 있음(프로세스, 뮤택스 같은거))
정확하게 하는 일은 인자로 넘어온 것이 Signaled 상태가 될때까지 기다리는 것, 즉, 종료될때까지 기다리는것
DWORD WaitForSingleObject(
HANDLE hHandle, //handle to a kernel object 자기가 대기하고자 하는 핸들
DWORD dwMilliseconds //time-out interval, 이 시간이 지나도 스레드가 깨어나도록 타임아웃을 줌
);반환값
WAIT_OBJECT_0 : 이 타임아웃 이내에 스레드가 정상적으로 종료됨
WAIT_TIME_OUT : 이 시간이 지나가도록 스레드가 종료되지 않음, 여전히 스레드가 실행중
WAIT_ABANDONED : 스레드가 뮤택스의 소유권을 놓지않고 스레드를 종료함
WAIT_FAILED : 커널오브젝트의 핸들을 넘겨줘야하는데 잘못된 값을 넘겨줌
스레드가 종료될때까지 무한정 대기하고 싶으면 WaitForSingleObject(hThrdINFINITE); 사용
+커널오브젝트(커널오브젝트 : 스레드, 프로세스, 뮤택스, 세마포어)
Signaled, Nonsignaled 중 하나의 상태를 가짐, 실행중에 Nonsignaled 종료되면 Signaled
여러개의 스레드 대기
WaitForMultipleObject()
Synchronization objects
Critical Section(non kernel obejct) - 두 개 이상의 Thread가 하나의 Resource를 공유
Mutexes(Mutually Exclusive) - Critical Section + Multi Processes)
Semaphores - Resource에 동시에 접근할 수 있는 Threads의 개수 설정
Event - 순차적으로 수행해야 하는 두개 이상의 Thread 처리, 공유 데이터에 대한 접근을 제어하기 위한 Mutex나 Semaphore와는 달리 Event는 어떤 연산이 끝났을 때 Signal시키기 위한 것
용어
Win32 스레드 과정
- Creating
- Monitoring
- Exiting a thread
- Closing a thread
function call(함수호출) vs thread start up(스레드)
function call : 함수를 호출하는 시점부터 시작, 함수가 끝나야 리턴이 되서 그 함수를 호출한 콜러쪽에 제어권이 넘어감, 순차적으로 시행됨(함수 호출하는 caller가 함수의 제어권 넘어갔다 리턴하면 caller가 제어권 돌려받음. 이후 함수 부분 다음부터 이어서 실행, 메인에서 함수로 넘어갔다가 함수 끝나면 메인으로 다시 돌아와서 그 다음 이어가서 함, 즉 순차적인 진행)
thread start up : 어떤 function을 실행한다는 점에서는 function call과 동일함 그러나 스레드를 생성하는 시점에 그 함수가 바로 시작된다는 것을 보장할 수 없음. 스레드가 시작하는 지점을 예측할수 없음 -> 불확실성 (프로세스에 속도에 따라, 스레드가 어떤일을 하냐, 프로세스가 얼마나 바쁘냐에 따라 등에 따라 달라짐)(스레드는 실행되면 원래 스레드(caller)와는 분리되서 독자적으로 실행됨)(스레드가 레디에서 러닝상태로 넘어가는 것은 운영체제의 스케줄링 영역에서 설정됨 즉 우리가 제어할 수 없음)