Transcript IT COOKBOOK

Chapter 05.
멀티스레드
 학습 목표
IT COOKBOOK
• 멀티스레드의 필요성을 이해하고 기본 개념을 익힌
다.
• 멀티스레드를 이용하여 TCP 서버를 작성한다.
• 스레드 동기화 기법을 익힌다.
한빛미디어㈜
-1-
ehanbit.net
 프로세스와 스레드 (1/2)
IT COOKBOOK
• 용어
– 프로세스(process)
• 메모리를 비롯한 각종 리소스를 담고 있는 컨테이너(container)로
서 정적인 개념
– 스레드(thread)
• 실제 CPU 시간을 할당받아 수행되는 실행 단위로서 동적인 개념
– 주 스레드(primary thread)
• main() 또는 WinMain() 함수에서 시작되는 스레드로, 프로세스가
시작할 때 생성
– 컨텍스트 전환(context switch)
• CPU와 운영체제의 협동으로 이루어지는 스레드 실행 상태의 저장
과 복원 작업
한빛미디어㈜
-2-
ehanbit.net
 프로세스와 스레드 (2/2)
IT COOKBOOK
• 컨텍스트 전환 과정
① ②
① ②
CPU
스레드①
레지스터
CPU
스레드②
레지스터
① ②
① ②
스레드①
레지스터
CPU
CPU
스레드②
레지스터
한빛미디어㈜
-3-
ehanbit.net
 스레드 생성과 종료 (1/6)
IT COOKBOOK
• 스레드 생성에 필요한 요소
– 스레드 함수(thread function)의 시작 주소
– 스레드 함수 실행시 사용할 스택 영역의 크기
한빛미디어㈜
-4-
ehanbit.net
 스레드 생성과 종료 (2/6)
IT COOKBOOK
• 프로세스의 주소 공간
스레드 ①, ②
– 두 개의 함수
– 세 개의 스레드
주 스레드
f()
{
...
}
main()
{
...
}
코드
주 스레드의
실행 스택
스레드 ①의
실행 스택
스레드 ②의
실행 스택
한빛미디어㈜
-5-
ehanbit.net
 스레드 생성과 종료 (3/6)
IT COOKBOOK
• CreateThread() 함수
– 스레드를 생성한 후 스레드 핸들(thread handle)을 리턴
HANDLE CreateThread (
LPSECURITY_ATTRIBUTES lpThreadAttributes, // NULL
SIZE_T dwStackSize, // 0
LPTHREAD_START_ROUTINE lpStartAddress, // 스레드 함수
LPVOID lpParameter, // 스레드 함수 인자
DWORD dwCreationFlags, // 0 또는 CREATE_SUSPENDED
LPDWORD lpThreadId // 스레드 ID
);
성공: 스레드 핸들, 실패: NULL
한빛미디어㈜
-6-
ehanbit.net
 스레드 생성과 종료 (4/6)
IT COOKBOOK
• 스레드 함수 정의
DWORD WINAPI ThreadProc (LPVOID lpParameter)
{
...
}
한빛미디어㈜
-7-
ehanbit.net
 스레드 생성과 종료 (5/6)
IT COOKBOOK
• 스레드 종료 방법
①
②
③
④
한빛미디어㈜
스레드 함수가 리턴
스레드 함수 내에서 ExitThread() 함수를 호출
TerminateThread() 함수를 호출
주 스레드가 종료하면 모든 스레드가 종료
-8-
ehanbit.net
 스레드 생성과 종료 (6/6)
IT COOKBOOK
• 스레드 종료 함수
void ExitThread (
DWORD dwExitCode // 종료 코드
);
BOOL TerminateThread (
HANDLE hThread, // 종료할 스레드를 가리키는 핸들
DWORD dwExitCode // 종료 코드
);
성공: 0이 아닌 값, 실패: 0
한빛미디어㈜
-9-
ehanbit.net
 스레드 조작 – 우선 순위 (1/5)
IT COOKBOOK
• 용어
– 스레드 스케줄링(thread scheduling)
• 윈도우가 각 스레드에게 CPU 시간을 적절히 분배하기 위한 정책
– 우선순위 클래스(priority class)
• 프로세스 속성으로, 한 프로세스가 생성한 스레드는 모두 동일한
우선순위 클래스를 가짐
– 우선순위 레벨(priority level)
• 스레드 속성으로, 한 프로세스에 속한 스레드 사이에서 상대적인
우선순위를 결정할 때 사용
– 기초 우선순위(base priority)
• 우선순위 클래스와 우선순위 레벨을 결합한 값으로, 스레드 스케
줄링에 사용
한빛미디어㈜
- 10 -
ehanbit.net
 스레드 조작 – 우선 순위 (2/5)
IT COOKBOOK
• 우선 순위 클래스
– REALTIME_PRIORITY_CLASS(실시간)
– HIGH_PRIORITY_CLASS(높음)
– ABOVE_NORMAL_PRIORITY_CLASS(보통 초과; 윈도우
2000/XP/2003)
– NORMAL_PRIORITY_CLASS(보통)
– BELOW_NORMAL_PRIORITY_CLASS(보통 미만; 윈도우
2000/XP/2003)
– IDLE_PRIORITY_CLASS(낮음)
한빛미디어㈜
- 11 -
ehanbit.net
 스레드 조작 – 우선 순위 (3/5)
IT COOKBOOK
• 우선 순위 레벨
–
–
–
–
–
–
–
한빛미디어㈜
THREAD_PRIORITY_TIME_CRITICAL
THREAD_PRIORITY_HIGHEST
THREAD_PRIORITY_ABOVE_NORMAL
THREAD_PRIORITY_NORMAL
THREAD_PRIORITY_BELOW_NORMAL
THREAD_PRIORITY_LOWEST
THREAD_PRIORITY_IDLE
- 12 -
ehanbit.net
스레드 조작 – 우선 순위 (3/5)
한빛미디어㈜
IT COOKBOOK
- 13 -
ehanbit.net
 스레드 조작 – 우선 순위 (4/5)
IT COOKBOOK
• 우선 순위 기반 스레드 스케줄링
(낮음) 기초 우선순위 (높음)
...
세 개의 스레드를
교대로 수행
스레드
스케줄러
CPU
한빛미디어㈜
- 14 -
ehanbit.net
 스레드 조작 – 우선 순위 (5/5)
IT COOKBOOK
• 우선 순위 레벨 조작 함수
BOOL SetThreadPriority (
HANDLE hThread, // 스레드 핸들
int nPriority // 우선순위 레벨값
);
성공: 0이 아닌 값, 실패: 0
int GetThreadPriority (
HANDLE hThread // 스레드 핸들
);
성공: 우선순위 레벨값,
실패: THREAD_PRIORITY_ERROR_RETURN
한빛미디어㈜
- 15 -
ehanbit.net
 다중 쓰레드 지원 환경 설정
한빛미디어㈜
IT COOKBOOK
- 16 -
ehanbit.net
 스레드 조작 – 스레드 종료 대기 (1/4)
IT COOKBOOK
• WaitForSingleObject() 함수
– 특정 스레드가 종료할 때까지 대기
DWORD WaitForSingleObject (
HANDLE hHandle,
DWORD dwMilliseconds
);
성공: WAIT_OBJECT_0 또는 WAIT_TIMEOUT,
실패: WAIT_FAILED
• WaitForSingleObject() 함수 사용 예
HANDLE hThread = CreateThread(...);
WaitForSingleObject(hThread, INFINITE);
한빛미디어㈜
- 17 -
ehanbit.net
 스레드 조작 – 스레드 종료 대기 (2/4)
IT COOKBOOK
• WaitForMultipleObjects() 함수
– bWaitAll =TRUE 이면 두 개 이상의 스레드가 종료할 때까지 대기
– bWaitAll =FALSE 이면 한 개 스레드가 종료할 때 바로 리턴
DWORD WaitForMultipleObjects (
DWORD nCount,
쓰레드의 갯수
const HANDLE* lpHandles,
BOOL bWaitAll,
DWORD dwMilliseconds
);
성공: WAIT_OBJECT_0 ~ WAIT_OBJECT_0 + nCount-1
또는 WAIT_TIMEOUT,
실패: WAIT_FAILED
한빛미디어㈜
- 18 -
ehanbit.net
 스레드 조작 – 스레드 종료 대기 (3/4)
IT COOKBOOK
• WaitForMultipleObjects() 함수 사용 예 ①
// 모든 스레드 종료를 기다릴 경우
HANDLE hThread[2];
HANDLE hThread[0] = CreateThread(...);
HANDLE hThread[1] = CreateThread(...);
WaitForMultipleObjects(2, hThread, TRUE, INFINITE);
한빛미디어㈜
- 19 -
ehanbit.net
 스레드 조작 – 스레드 종료 대기 (4/4)
IT COOKBOOK
• WaitForMultipleObjects() 함수 사용 예 ②
// 두 스레드 중 하나의 종료를 기다릴 경우
HANDLE hThread[2];
HANDLE hThread[0] = CreateThread(...);
HANDLE hThread[1] = CreateThread(...);
DWORD retval = WaitForMultipleObjects(2, hThread, FALSE, INFINITE);
switch(retval){
case WAIT_OBJECT_0:
// hThread[0] 종료
break;
case WAIT_OBJECT_0+1:
// hThread[1] 종료
break;
case WAIT_FAILED:
// 오류 발생
break;
}
한빛미디어㈜
- 20 -
ehanbit.net
 스레드 조작 – 실행 중지와 재실행 (1/2)
IT COOKBOOK
• 실행 중지 함수 ①
DWORD SuspendThread (
HANDLE hThread // 스레드 핸들
);
성공: 중지 횟수, 실패: -1
• 재실행 함수
DWORD ResumeThread (
HANDLE hThread // 스레드 핸들
);
성공: 중지 횟수, 실패: -1
한빛미디어㈜
- 21 -
ehanbit.net
 스레드 조작 – 실행 중지와 재실행 (2/2)
IT COOKBOOK
• 실행 중지 함수 ②
– 스레드가 실행을 멈추고 일정 시간동안 대기
void Sleep (
DWORD dwMilliseconds // 밀리초(ms)
);
한빛미디어㈜
- 22 -
ehanbit.net
 멀티스레드 TCP 서버 (1/3)
IT COOKBOOK
• 기본 구조
DWORD WINAPI ProcessClient(LPVOID arg)
{
// 전달된 소켓 ③
SOCKET client_sock = (SOCKET)arg;
// 클라이언트 정보 얻기 ④
addrlen = sizeof(clientaddr);
getpeername(client_sock, (SOCKADDR *)&clientaddr, &addrlen);
// 클라이언트와 데이터 통신 ⑤
while(1){
...
}
closesocket(client_sock);
return 0;
}
한빛미디어㈜
- 23 -
ehanbit.net
 멀티스레드 TCP 서버 (2/3)
IT COOKBOOK
• 기본 구조 (cont’d)
int main(int argc, char* argv[])
{
...
while(1){
// 클라이언트 접속 수용 ①
client_sock = accept(listen_sock, ...);
...
// 스레드 생성 ②
CreateThread(NULL, 0, ProcessClient,
(LPVOID)client_sock, 0, &ThreadId);
}
...
}
한빛미디어㈜
- 24 -
ehanbit.net
 멀티스레드 TCP 서버 (3/3)
IT COOKBOOK
• 소켓과 연관된 주소 정보 얻기
int getpeername (
SOCKET s,
struct sockaddr* name,
int* namelen
);
성공: 0, 실패: SOCKET_ERROR
int getsockname (
SOCKET s,
struct sockaddr* name,
int* namelen
);
성공: 0, 실패: SOCKET_ERROR
한빛미디어㈜
- 25 -
ehanbit.net
 스레드 동기화 (1/4)
IT COOKBOOK
• 스레드 동기화(thread synchronization) 필요성
– 멀티스레드를 사용하는 프로그램에서 두 개 이상의 스레
드가 공유 데이터를 접근하는 경우
공유 변수
int money = 1000
스레드 1
한빛미디어㈜
스레드 2
...
...
① read money into ECX
① read money into ECX
② ECX = ECX + 2000
② ECX = ECX + 4000
③ write ECX into money
③ write ECX into money
...
...
- 26 -
ehanbit.net
 스레드 동기화 (2/4)
IT COOKBOOK
• 다양한 스레드 동기화 기법
종류
임계영역
(critical section)
뮤텍스
(mutex)
주요 용도
공유 리소스에 대해 오직 하나의 스레드 접근만 허용
(한 프로세스에 속한 스레드에만 사용 가능)
(가장 저급의 동기화 수준)
공유 리소스에 대해 오직 하나의 스레드 접근만 허용
(서로 다른 프로세스에 속한 스레드 동기화에 유용)
(critical section의 확장 개념)
이벤트
(event)
특정 사건 발생을 다른 스레드에게 알림
(가장 널리 사용되며, 시그널에 의한 동기화 처리)
세마포
(semaphore)
한정된 개수의 자원을 여러 스레드가 사용하려고 할 때,
접근을 제한
대기 가능 타이머
(waitable timer)
특정 시간이 되면 대기 중인 스레드를 깨움
한빛미디어㈜
- 27 -
ehanbit.net
 스레드 동기화 (3/4)
IT COOKBOOK
• 스레드 동기화 원리
스레드 1
매개체
진행
한빛미디어㈜
스레드 2
대기
- 28 -
ehanbit.net
 스레드 동기화 (4/4)
IT COOKBOOK
• 스레드 동기화 원리 (cont’d)
비신호 상태
신호 상태
동기화 객체
동기화 객체
Wait*() 함수로 감지
한빛미디어㈜
- 29 -
ehanbit.net
 이벤트 객체 (1/3)
IT COOKBOOK
• 이벤트 객체(event object)
– 특정 사건 발생을 다른 스레드에게 알릴 때 주로 사용
• 이벤트 객체를 이용한 동기화 예
① 이벤트 객체를 비신호 상태로 생성
② 한 스레드가 작업을 진행하고, 나머지 스레드는 이벤트
객체에 대해 Wait*() 함수를 호출함으로써 이벤트 객체가
신호 상태가 되기를 기다림
③ 스레드가 작업을 완료하면, 이벤트를 신호 상태로 바꿈
④ 기다리고 있던 모든 스레드가 깨어나서 작업을 진행
한빛미디어㈜
- 30 -
ehanbit.net
 이벤트 객체 (2/3)
IT COOKBOOK
• 이벤트 객체 상태 변경
BOOL SetEvent (HANDLE hEvent) ; // 비신호 상태  신호 상태
BOOL ResetEvent (HANDLE hEvent) ; // 신호 상태  비신호 상태
• 이벤트 객체의 종류
– 자동 리셋(auto-reset) 이벤트
– 수동 리셋(manual-reset) 이벤트
• 쓰레드 1 : 읽기 전용 쓰레드
• 쓰레드 2 : 쓰기 전용 쓰레드
WaitForSingleObject(hEvent, INFINITE);
ResetEvent(hEvent);
WaitForSingleObject(hEvent, INFINITE);
ResetEvent(hEvent);
//읽기 작업 수행
//쓰기 작업 수행
SetEvent(hEvent)
SetEvent(hEvent)
한빛미디어㈜
- 31 -
ehanbit.net
 이벤트 객체 (3/3)
IT COOKBOOK
• 이벤트 객체 생성
HANDLE CreateEvent (
LPSECURITY_ATTRIBUTES lpEventAttributes,
BOOL bManualReset,
BOOL bInitialState,
LPCTSTR lpName
);
성공: 이벤트 핸들, 실패: NULL
Use the CloseHandle function to close the handle.
BOOL CloseHandle( HANDLE hObject);
한빛미디어㈜
- 32 -
ehanbit.net
 CreateThread, _beginThreadex, _beginThread, AfxBeginThread
IT비교
COOKBOOK
•
CreateThread/ExitThread를 C/C++라이브러리와 함께 사용할 경우, C/C++ 라
이브러리가 멀티쓰레드 환경에서 문제를 일으킬 수 있다.
•
_beginthread/_endthread 는 쓰레드를 생성하고 난후 바로 ::CloseHandle 함수
를 통해 바로 쓰레드의 핸들을 제거해버린다.
•
•
•
•
C/C++ 라이브러리 함수를 사용하는 응용프로그램에서는
_beginthreadex/_endthreadex를 사용하는 것이 더 바람직하다.
•
•
•
•
•
쓰레드 재사용 안된다
일시정지된 상태의 쓰레드 생성 안된다.
보안특성을 가진 쓰레드 생성 안된다
_beginthreadex/_endthreadex 가 C/C++ 라이브러리가 멀티쓰레드 환경에서 문제없
이 동작하도록 부가적인 코드를 수행한다.
_endthread, _endthreadex는 _beginthread, _beginthreadex에 의해 생성된 thread
가 종료될 때 자동 호출되며, 직접 호출할 수도 있다.
_beginthreadex를 이용하는 경우, 반드시 ::CloseHandle을 통해 thread의 handle을
명시적으로 제거해주어야한다.
_beginthreadex 나 _beginthread를 사용하기위해서는 #include<process.h>
MFC 라이브러리인 경우는 AfxBeginThread를 사용하는 것이 좋다.
한빛미디어㈜
- 33 -
ehanbit.net
 _beginthreadex
IT COOKBOOK
• unsigned long _beginthread( void( __cdecl *start_address )( void * ),
unsigned stack_size, void *arglist );
• unsigned long _beginthreadex( void *security, unsigned stack_size,
unsigned ( __stdcall *start_address )( void * ), void *arglist, unsigned
initflag, unsigned *thrdaddr );
Parameters
•
•
•
•
•
•
한빛미디어㈜
start_address : Start address of routine that begins execution of new thread
stack_size : Stack size for new thread or 0
Arglist : Argument list to be passed to new thread or NULL
Security : Security descriptor for new thread; must be NULL for Windows 95
applications
Initflag : Initial state of new thread (0 for running or CREATE_SUSPEND for
suspended)
Thrdaddr : Points to a 32-bit variable that receives the thread identifier
- 34 -
ehanbit.net