스레드에 대한 기본 이론
Win32 스레드 생성
- 한 Process는 최소 1개 이상의 Thread를 갖는다. 젤 처음 생성되는 메인스레드
- Thread는 개별화된 흐름(문맥) 과 전용스택을 갖는 실행의 단위이다.
- 모든 Thread는 자신이 속한 Process의 가상 메모리공간을 공유한다.
- 개별 ID(부호가 없는 정수)와 핸들 -> 제어 용도
Win32 스레드 속성
- ID, Handle
- 우선순위(highest, above normal)
- 상태 (run, suspended , terminated)
- 친화력 (Cpu core)
주로 gui 앱 같은곳에서 event loop 방식으로 해결함 -> gui event thread는 오래걸리는 작업들은 새로운 스레드에서 작업을 진행해서 반응성을 높게 해줌
스레드 생성 및 종료 대기
CreateThread()
int main()
{
std::cout << "main() - Begin" << std::endl;
DWORD dwThreadId = 0;
HANDLE hThread = ::CreateThread(
NULL,
0,
ThreadFunction,
(LPVOID)"PARAM",
0,
&dwThreadId);
if (hThread == NULL) {
}
std::cout << "main() - WaitForSingleObject() - before" << std::endl;
::WaitForSingleObject(hThread, INFINITE);
::CloseHandle(hThread);
std::cout << "main() - End" << std::endl;
return 0;
}
dwStackSize 를 0으로 주게되면 compiler에 따른 stack size (보통 1MB) 로 된다.
lpStartAddress 에는 실행 시킬 function을 적게 된다. thread에서 실행될 함수는 return에서 정상종료 하도록 동기화 해야함
dwCreationFlags = 스레드를 만들자 마자 바로 실행시킬 것인가?
WaitForSingleObject = 특정 thread handle에 대하여 종료될때까지 대기하게 된다. timeout 도 존재한다. 도중에 에러가 발생하면 getLastError를 호출해서 MSDN 에서 찾아봐야함 -> 추후 추가 설명.
_beginthreadex() 함수
사실상 CreateThread랑 똑같다.
UINT WINAPI ThreadFunction(LPVOID pParam)
{
std::cout << "ThreadFunction() - Begin" << std::endl;
std::cout << (const char*)pParam << std::endl;
std::cout << "ThreadFunction() - End" << std::endl;
return 0;
}
int main()
{
std::cout << "main() - Begin" << std::endl;
UINT nThreadId = 0;
HANDLE hThread = (HANDLE)::_beginthreadex(
NULL,
0,
ThreadFunction,
(LPVOID)"PARAM",
0,
&nThreadId);
if (hThread == NULL) {
}
::WaitForSingleObject(hThread, INFINITE);
::CloseHandle(hThread);
std::cout << "main() - End" << std::endl;
return 0;
}
안에 들어가는 매개 변수는 똑같지만 큰 차이가 하나 있다.
c runtime library에서 정적 변수 (static) 을 써서 여러 스레드가 동시에 해당 library 를 접근하면 엉킬 가능성이 있다면 beginthreadex로 스레드를 생성해줘야한다.
java 의 Thread Local 개념인 TLS를 적용한후에 CreateThread를 호출하게 된셈이다. stackoverflow에서도 무조건 beginthreadex를 쓰라한다.
스레드 제어 및 상태전환
- 스레드 핸들로 제어 대상 선택
- 스레드를 일시 정지하거나 재시작
- 스레드 스위칭을 야기하며 그에 따른 오버헤드 발생
- 스레드를 강제로 종료
- 스레드 우선순위 변경
OpenThread 함수로 어떤 스레드를 어떤 권한으로 조절할지 정하게 된다.
다른 프로세스에서 다른 프로세스의 스레드도 위 함수로 제어가 가능하다.
#include <iostream>
#include <process.h>
#include <windows.h>
int g_bFlag = FALSE;
UINT WINAPI ThreadFunction(LPVOID pParam)
{
std::cout << "ThreadFunction - begin" << std::endl;
g_bFlag = TRUE;
while (g_bFlag)
{
std::cout << "Worker thread - while loop" << std::endl;
::Sleep(1000);
}
std::cout << "ThreadFunction - End" << std::endl;
return 0;
}
int main()
{
std::cout << "main() - Begin" << std::endl;
UINT nThreadId = 0;
HANDLE hThread = (HANDLE)::_beginthreadex(
NULL,
0,
ThreadFunction,
(LPVOID)"PARAM",
0,
&nThreadId);
if (hThread == NULL) {
std::cout << "ERROR: Failed to begin thread." << std::endl;
return 0;
}
::Sleep(2000);
std::cout << "main() - SuspendThread()" << std::endl;
::SuspendThread(hThread);
for (int i = 0; i < 3; ++i)
{
::WaitForSingleObject(hThread, 1000);
std::cout << "main() - WaitForSingleObject(1000)" << std::endl;
}
::ResumeThread(hThread);
std::cout << "main() - ResumeThread()" << std::endl;
::Sleep(2000);
g_bFlag = FALSE;
::WaitForSingleObject(hThread, INFINITE);
::CloseHandle(hThread);
std::cout << "main() - End" << std::endl;
return 0;
}
beginthreadex로 스레드를 생성한 후에 suspendThread로 중지 시키고 ResumeThread로 다시 가동시킨다.
resume 하지 않으면 WaitForSingleObject에서 무한히 대기하다가 timeout이 나게 될것이다.
Sleep() 함수
- 스레드를 일정 시간 동안 suspend 시켰다가 시간이 지나면 자동으로 Resume 되어 Run 상태로 전환
- 자기 자신에게 suspend -> resume 할때 사용함
- 보통 설정한 시간보다 더 많은 시간이 흐르며 정확성이 떨어짐
- 우연에 맡기는 코드를 만드는 주범
while loop 에서 sleep을 넣어주면 cpu load 100을 찍지 않고 0~1로 확줄어든다.
'Operating System > Windows 시스템 프로그래밍 - 기본' 카테고리의 다른 글
프로세스 관리 (0) | 2023.07.18 |
---|---|
메모리 시스템 (0) | 2023.07.15 |
Win32 파일 입/출력 (0) | 2023.07.10 |
스레드 동기화 (0) | 2023.07.07 |
기본 이론 (0) | 2023.07.03 |