본문 바로가기

Research/Windows

[ 책 정리 ] Thread - 1





스레드


Windows의 기본 실행 단위.

다중 스레드 프로그래밍에서 병렬성의 장점을 극대화하기 위해 스레드 실행의 조직화 / 중재에 신경 써야 한다.


다중 스레드 동작방식에 비해, 단일 스레드 프로세스들을 동시에 실행하는 방식의 단점

1. 프로세스 전환 비용

2. 공유 메모리를 제외하고는 프로세스들 사이의 결합도가 높지 않다. 열린 파일과 같은 자원을 공유하기 어렵다.

3. 병렬이면서 상호작용하는 태스크(하나는 계산 수행, 하나는 입출력) 관리는 어렵고 비효율적이다.

4. 멀티코어 PC의 경우 각각의 스레드를 프로세서들에 할당할 수 있으며 대체로 성능 향상에 도움이 된다.



관점

"스레드는 프로그램의 설계와 구현을 단순화한다",

"몇몇 규칙과 모형에 따르면 성능 향상과 신뢰성, 가독성, 유지보수성을 높일 수 있다."


    

스레드의 기초

프로세스 내의 스레드들은 자료와 코드를 공유한다.

공유 자료 이외에도 스레드 자신만의 고유 저장공간을 가진다. 그러나 완전하게 보호되는 것은 아니며 이것은 프로그래머에게 책임이 있다.


고유 저장공간의 종류에는 스택, 그리고 아규먼트, TLS 영역이 있다.


스레드 관리


1. CreateThread


HANDLE CreateThread ( LPSECURITY_ATTRIBUTES lpsa,

DWORD dwStackSize,

LPTHREAD_START_ROUTINE lpStartAddr,

LPVOID lpThreadParm,

DWORD dwCreationFlags,

LPDWORD lpThreadId );


리턴값 : 스레드 핸들

LPSECURITY_ATTRIBUTES lpsa

보안 구조체. 특별한 경우가 아니면 NULL

DWORD dwStackSize

스레드의 스택 크기. 보통 0으로 넣으면 기본 스택 크기 지정된다.

LPTHREAD_START_ROUTINE lpStartAddr

스레드가 돌아갈 함수 포인터.

이 함수 포인터는 "DWORD WINAPI threadname(LPVOID)" 형태여야 한다.

LPVOID lpThreadParm

스레드에 필요한 파라미터

DWORD dwCreationFlags

스레드가 언제 실행될 지 정해준다.

0을 지정하면 바로 실행

CREATE_SUSPEND 지정하면 일시 정지 상태로 생성되며 실행하려면 ResumeThread 호출해야 한다.

LPDWORD lpThreadId

생성된 스레드 ID 를 받을 변수가 들어간다. 필요 없으면 걍 NULL 하면 된다.


2. ExitThread


VOID ExitThread ( DWORD dwExitCode )


리턴값 : 없음.

흔히 쓰이는 것은 return 을 통해서 스레드가 스스로 종료되게 하는 방식.

스레드 종료 시에는 스택이 해제되며 모든 핸들이 signal 상태가 된다. 만약 DLL 과 링크되어 있다면 DllMain 이 호출되며 reason은 DLL_THREAD_DETACH 인수를 갖는다.

TerminateThread 함수를 이용해서 다른 스레드를 종료시킬 수도 있지만 스택이 해제되지 않고 DLL 들에게도 통지가 가지 않는다.



3. GetExitCodeThread


BOOL GetExitCodeThread (    HANDLE hThread,

LPDWORD lpExitCode )


hThread : [IN]

lpExitCode : [OUT]


스레드가 종료되더라도 CloseHandle 을 통해서 마지막 핸들이 닫힐 때 까지는 계속해서 존재한다.

다른 스레드(스레드의 종료를 기다린다던가..)에서 이 함수를 통해 종료 코드를 얻을 수 있다. 

lpExitCode 가 STILL_ACTIVE 이면 스레드가 실행 중인 것.



4. thread identity


GetCurrentThread

GetCurrentThreadId

GetThreadId

OpenThread


다른 페이지에서 설명했던 것 같다.



5. GetProcessIdOfThread


주어진 핸들에 해당하는 스레드의 프로세스 ID를 찾아 준다.

이를 통해 다른 프로세스 핸들을 얻거나 (OpenProcess) 프로세스의 스레드를 관리할 수 있다.



6. GetThreadIOPendingFlag


이건 잘 모르겠다. 예제를 찾아보고 써 봐야 이해가 갈듯...



7. Thread suspend / resume


DWROD ResumeThread (HANDLE hThread)

DWORD SuspendThread (HANDLE hThread)


리턴 : 실패 시에 0xFFFFFFFF

스레드에는 suspend count 라는 게 있다. 이 횟수가 0일때만 스레드가 실행 될 수 있다.

한 스레드가 다른 스레드의 suspend count 를 증가 (SuspendThread) 혹은 감소 (ResumeThread) 시킬 수 있다.



8. 스레드 종료 대기


WaitForSingleObject / WaitForMultipleObject.

얘네는 지정된 객체 (프로세스든 스레드든) 가 시그널signaled되길 기다린다. ExitThread / TerminateThread 가 스레드를 시그널 상태로 설정하며, 그러면 해당 스레드를 기다리던 다른 모든 스레드가 해제된다. 뮤텍스나 이벤트와 같은 특별한 경우를 제외하면, 시그널 상태가 된 스레드 핸들이 시그널이 되지 않은 상태로 돌아가는 일은 없다. 비슷하게, ExitProcess 는 프로세스와 모든 스레드를 시그널 상태로 만든다.




기타


CreateThread 대신 _beginthreadex 를 사용할 것. ExitThread 대신 _endthreadex를 사용할 것.

인수들은 모두 같으나, _beginthreadex 의 경우 리턴값을 그대로 핸들로 사용하면 경고가 뜬다.

전처리기 정의로 _MT를 주던지, 옵션에서 다중 스레드 DLL (/MD)를 선택하던지.





'Research > Windows' 카테고리의 다른 글

NTSTATUS  (1) 2014.08.12
CrtlsalidHeapPointer, pUserData 에러  (0) 2014.07.09
C++ / Mysql Connector  (0) 2013.10.18
GetProcessHandleCount  (0) 2013.07.31
CreateProcess  (0) 2013.07.31