Presentation is loading. Please wait.

Presentation is loading. Please wait.

멀티스레드 Chapter 05. * 학습목표 멀티스레드의 필요성을 이해하고 기본 개념을 익힘.

Similar presentations


Presentation on theme: "멀티스레드 Chapter 05. * 학습목표 멀티스레드의 필요성을 이해하고 기본 개념을 익힘."— Presentation transcript:

1 멀티스레드 Chapter 05. * 학습목표 멀티스레드의 필요성을 이해하고 기본 개념을 익힘.
멀티스레드를 이용하여 TCP 서버를 작성 스레드 동기화 기법을 익힘

2 프로세스와 스레드 - (1) 용 어 프로세스(process)
메모리를 비롯한 각종 리소스를 담고 있는 컨테이너(container)로서 정적인 개념 스레드(thread) 실제 CPU 시간을 할당받아 수행되는 실행 단위로서 동적인 개념 주 스레드(primary thread) main() 또는 WinMain() 함수에서 시작되는 스레드로, 프로세스가 시작할 때 생성 컨텍스트 전환(context switch) – (뒤에 그림 참조 !) CPU와 운영체제의 협동으로 이루어지는 스레드 실행 상태의 저장과 복원 작업

3 프로세스와 스레드 - (2) 컨텍스트 전환 과정 CPU 스레드① 레지스터 스레드② 실행 중지 교환 중지 실행 교환

4 스레드 생성과 종료 - (1) 스레드 생성에 필요한 요소 프로세스의 주소 공간 f() { ... } main() 코드
주 스레드의 실행 스택 스레드 ①의 코드 스레드 ②의 주 스레드 스레드 ①, ② 스레드 생성에 필요한 요소 스레드 함수(thread function)의 시작 주소 스레드 함수 실행 시 사용할 스택 영역의 크기 프로세스의 주소 공간 2개의 함수 3개의 스레드

5 스레드 생성과 종료 - (2) CreateThread() 함수 스레드 함수 정의
스레드를 생성한 후 스레드 핸들(thread handle)을 리턴 HANDLE CreateThread ( LPSECURITY_ATTRIBUTES lpThreadAttributes, // NULL SIZE_T dwStackSize, // 0 LPTHREAD_START_ROUTINE lpStartAddress, // 스레드 함수 시작 주소 LPVOID lpParameter, // 스레드 함수 인자(void형 포인터 32비트) DWORD dwCreationFlags, // 0(바로 실행) 또는 CREATE_SUSPENDED(ResumeThread( ) 호출 후 실행 LPDWORD lpThreadId // 스레드 ID(보통 Null값) ) ; 성공: 스레드 핸들, 실패: NULL 스레드 함수 정의 DWORD WINAPI ThreadProc (LPVOID lpParameter) { ... }

6 스레드 생성과 종료 - (3) 스레드 종료 방법 스레드 종료 함수 ① 스레드 함수가 리턴(많이 사용)
② 스레드 함수 내에서 ExitThread() 함수를 호출(많이 사용) ③ TerminateThread() 함수를 호출(극단적인 경우에만 사용) ④ 주 스레드가 종료하면 모든 스레드가 종료(비추전) 스레드 종료 함수 void ExitThread ( DWORD dwExitCode // 종료 코드 ) ; BOOL TerminateThread ( HANDLE hThread, // 종료할 스레드를 가리키는 핸들 DWORD dwExitCode // 종료 코드 ) ; 성공: 0이 아닌 값, 실패: 0

7 예제 1 pp. 152 ~ pp. 155 ExThread1.cpp 중요 !

8 스레드 조작 – 우선 순위 (1) 용 어 스레드 스케줄링(thread scheduling)
윈도우가 각 스레드에게 CPU 시간을 적절히 분배하기 위한 정책 우선순위 클래스(priority class) 프로세스 속성으로, 한 프로세스가 생성한 스레드는 모두 동일한 우선순위 클래스를 가짐 우선순위 레벨(priority level) 스레드 속성으로, 한 프로세스에 속한 스레드 사이에서 상대적인 우선순위를 결정할 때 사용 기초 우선순위(base priority) : 우선순위 클래스 + 우선순위 레벨 우선순위 클래스와 우선순위 레벨을 결합한 값으로, 스레드 스케줄링에 사용

9 스레드 조작 – 우선 순위 (2) 우선 순위 클래스 (Windows 작업 관리자) 우선 순위 레벨(위와 동일함)
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(낮음) 우선 순위 레벨(위와 동일함) THREAD_PRIORITY_TIME_CRITICAL (실시간) THREAD_PRIORITY_HIGHEST (높음) THREAD_PRIORITY_ABOVE_NORMAL (보통초과) THREAD_PRIORITY_NORMAL (보통) THREAD_PRIORITY_BELOW_NORMAL (보통 아래) THREAD_PRIORITY_LOWEST (낮음) THREAD_PRIORITY_IDLE (없음)

10 스레드 조작 – 우선 순위 (3) 우선 순위 기반 스레드 스케줄링 ... 스케줄러 (낮음) 기초 우선순위 (높음)
CPU 스레드 (낮음) 기초 우선순위 (높음) 3개의 스레드를 교대로 수행

11 스레드 조작 – 우선 순위 (4) 우선 순위 레벨 조작 함수 BOOL SetThreadPriority (
HANDLE hThread, // 스레드 핸들 int nPriority // 우선순위 레벨값 ) ; 성공: 0이 아닌 값, 실패: 0 int GetThreadPriority ( HANDLE hThread // 스레드 핸들 ) ; 성공: 우선순위 레벨값, 실패: THREAD_PRIORITY_ERROR_RETURN

12 예제 2 pp. 159 ~ pp. 160 ExThread2.cpp 중요 ! 바이러스 프로그램과 유사함

13 스레드 조작 – 스레드 종료 대기 (1) WaitForSingleObject() 함수
특정 스레드가 종료할 때까지 대기 WaitForSingleObject() 함수 사용 예 DWORD WaitForSingleObject ( HANDLE hHandle, DWORD dwMilliseconds ) ; 성공: WAIT_OBJECT_0 또는 WAIT_TIMEOUT, 실패: WAIT_FAILED HANDLE hThread = CreateThread(...); WaitForSingleObject(hThread, INFINITE);

14 스레드 조작 – 스레드 종료 대기 (2) WaitForMultipleObjects() 함수
두 개 이상의 스레드가 종료할 때까지 대기 DWORD WaitForMultipleObjects ( DWORD nCount, const HANDLE* lpHandles, BOOL bWaitAll, DWORD dwMilliseconds ) ; 성공: WAIT_OBJECT_0 ~ WAIT_OBJECT_0 + nCount-1 또는 WAIT_TIMEOUT, 실패: WAIT_FAILED

15 스레드 조작 – 스레드 종료 대기 (3) WaitForMultipleObjects() 함수 사용 예 ①
// 모든 스레드 종료를 기다릴 경우 HANDLE hThread[2]; HANDLE hThread[0] = CreateThread(...); HANDLE hThread[1] = CreateThread(...); WaitForMultipleObjects(2, hThread, TRUE, INFINITE); 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] 종료 case WAIT_FAILED: // 오류 발생 }

16 스레드 조작 – 실행 중지와 재실행 실행 중지 함수 ① DWORD SuspendThread (
재실행 함수 DWORD SuspendThread ( HANDLE hThread // 스레드 핸들 ) ; 성공: 중지 횟수, 실패: -1 DWORD ResumeThread ( HANDLE hThread // 스레드 핸들 ) ; 성공: 중지 횟수, 실패: -1 실행 중지 함수 ② 스레드가 실행을 멈추고 일정 시간 동안 대기 void Sleep ( DWORD dwMilliseconds // 밀리초(ms) ) ;

17 예제 3 pp. 164 ~ pp. 165 ExThread3.cpp 중요 ! 여기까지가 중간고사입니다.

18 멀티스레드 TCP 서버 - (1) 기본 구조 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; int main(int argc, char* argv[]) // 클라이언트 접속 수용 ① client_sock = accept(listen_sock, ...); // 스레드 생성 ② CreateThread(NULL, 0, ProcessClient, (LPVOID)client_sock, 0, &ThreadId); 기본 구조 뒷 참조! Client IP주소, 포토번호 얻음 부가적인 정보

19 멀티스레드 TCP 서버 - (2) 소켓과 연관된 주소 정보 얻기
int getpeername ( // 원격 IP주소, 원격 포트번호 리턴 SOCKET s, struct sockaddr* name, int* namelen ) ; 성공: 0, 실패: SOCKET_ERROR int getsockname ( // 지역 IP주소, 지역 포트번호 리턴 SOCKET s, struct sockaddr* name, int* namelen ) ; 성공: 0, 실패: SOCKET_ERROR

20 예제 4 pp. 168 ~ pp. 173 TCPServer2.cpp 4장의 TCPServer 예제를 수정하여 2개 이상의 Client를 처리하는 예제 4장의 TCPClient 예제는 그대로 사용할 것 ! 중요 !

21 스레드 동기화 (1) 스레드 동기화(thread synchronization) 필요성 공유 변수
멀티스레드를 사용하는 프로그램에서 두 개 이상의 스레드가 공유 데이터를 접근하는 경우 스레드 1 int money = 1000 ... ① read money into ECX ② ECX = ECX ③ write ECX into money 스레드 2 ② ECX = ECX 공유 변수 Money = 3000 Money = 5000 결국 쓰레드 2의 4000의 값은 없어짐

22 스레드 동기화 - (2) 다양한 스레드 동기화 기법 종류 주요 용도 임계영역(사용) (critical section)
공유 리소스에 대해 오직 하나의 스레드 접근만 허용 (한 프로세스에 속한 스레드에만 사용 가능) 뮤텍스(Report) (mutex) (서로 다른 프로세스에 속한 스레드에도 사용 가능) – 프로그램 삭제 시 주의(공유파일을 지움?? Yes or No) 이벤트(사용) (event) 특정 사건 발생을 다른 스레드에게 알림 세마포어(Report) (semaphore) 한정된 개수의 자원을 여러 스레드가 사용하려고 할 때, 접근을 제한 대기가능타이머 (waitable timer) (Report) 특정 시간이 되면 대기 중인 스레드를 깨움 중요! (운영체제수업)

23 스레드 동기화 - (3) 스레드 동기화 원리 매개체 스레드 1 스레드 2 진행 대기 동기화 객체 비신호 상태 신호 상태
P.161 참조(슬라이드 12, 13) WaitForSingleObject WaitForMultipleObject 동기화 객체 비신호 상태 신호 상태 Wait*() 함수로 감지 평소 특정조건이 성립 시 Case, if 구문

24 임계 영역 - (1) 임계 영역(critical section)
2개 이상의 스레드가 공유 리소스를 접근할 때, 오직 하나의 스레드 접근만 허용해야 하는 경우에 사용 특징 유저(user) 영역 메모리에 존재하는 구조체이므로 한 프로세스에 속한 스레드 동기화에만 사용 가능 일반적인 동기화 객체보다 빠르고 효율적 임계 영역 사용 예 #include <windows.h> CRITICAL_SECTION cs; // ① CRITICAL_SECTION 구조체 변수를 전역 변수로 선언 임계영역은 Application이 직접 메모리 할당 // 스레드 1 DWORD WINAPI Thread1(LPVOID arg) { ... EnterCriticalSection(&cs); // ③ 공유리소스를 사용 X -> 리턴, 공유리소스를 사용 0 -> 대기 // 공유 리소스 접근 LeaveCriticalSection(&cs); // ④ 공유리소스 종료 }

25 임계 영역 - (2) 임계 영역 사용 예 (계속) // 스레드 2 DWORD WINAPI Thread2(LPVOID arg)
{ ... EnterCriticalSection(&cs); // ③ // 공유 리소스 접근 LeaveCriticalSection(&cs); // ④ } int main() InitializeCriticalSection(&cs); // ② 임계 영역을 사용하기 전에 이 함수를 호출하여 초기화함. // 스레드 생성과 종료 DeleteCriticalSection(&cs); // ⑤ 임계 영역 사용이 끝나면 이 함수를 호출

26 예제 5 pp. 178 ~ pp. 182 ExCriticalSection.cpp 임계 영역을 사용하지 않을 경우 문제가 발생하는 극단적인 경우를 예제로 확인 중요 !

27 이벤트 객체 - (1) 이벤트 객체(event object) 이벤트 객체를 이용한 동기화 예 이벤트 객체 상태 변경
특정 사건 발생을 다른 스레드에게 알릴 때 주로 사용 이벤트 객체를 이용한 동기화 예 ① 이벤트 객체를 비신호 상태로 생성 ② 한 스레드가 작업을 진행하고, 나머지 스레드는 이벤트 객체에 대해 Wait*() 함수를 호출함으로써 이벤트 객체가 신호 상태가 되기를 기다림 ③ 스레드가 작업을 완료하면, 이벤트를 신호 상태로 바꿈 ④ 기다리고 있던 모든 스레드가 깨어나서 작업을 진행 이벤트 객체 상태 변경 이벤트 객체의 종류 자동 리셋(auto-reset) 이벤트 : ResetEvent 함수 사용 않아도 됨 수동 리셋(manual-reset) 이벤트 : ResetEvent 함수 사용해야 함 BOOL SetEvent (HANDLE hEvent) ; // 비신호 상태  신호 상태 BOOL ResetEvent (HANDLE hEvent) ; // 신호 상태  비신호 상태

28 이벤트 객체 - (2) 이벤트 객체 생성 HANDLE CreateEvent (
LPSECURITY_ATTRIBUTES lpEventAttributes, // 어려움 영역(일단 생략 !!) BOOL bManualReset, // True : 수동리셋이벤트, False : 자동리셋이벤트 BOOL bInitialState, // True : 신호 상태 시작, False : 비신호 상태로 시작 LPCTSTR lpName // Null : 이름없는 이벤트가 생성 ) ; 성공: 이벤트 핸들, 실패: NULL

29 예제 6 pp. 184 ~ pp. 187 ExEvent.cpp 공유 버퍼에 데이터를 쓰는 쓰레드 1개와 공유 버퍼로부터 데이터를 읽는 쓰레드 2개를 생성하도록 하는 예제 이 경우 1개의 쓰레드만 버퍼를 접근함. 접근 순서도 정해야함. 중요 !


Download ppt "멀티스레드 Chapter 05. * 학습목표 멀티스레드의 필요성을 이해하고 기본 개념을 익힘."

Similar presentations


Ads by Google