Presentation is loading. Please wait.

Presentation is loading. Please wait.

6장. 멀티스레드 멀티스레드 프로그래밍의 필요성을 이해하고 기본 개념을 익힌다.

Similar presentations


Presentation on theme: "6장. 멀티스레드 멀티스레드 프로그래밍의 필요성을 이해하고 기본 개념을 익힌다."— Presentation transcript:

1 6장. 멀티스레드 멀티스레드 프로그래밍의 필요성을 이해하고 기본 개념을 익힌다.
멀티스레드를 이용해 다중 클라이언트 처리가 가능한 서버를 작성할 수 있다. 스레드 동기화 기법을 이해하고 활용할 수 있다.

2 TCP 서버-클라이언트의 문제점 (1) 문제 ①: 동시에 둘 이상의 클라이언트 서비스 불가

3 TCP 서버-클라이언트의 문제점 (2) 문제 ① 해결책 서버가 각 클라이언트와 통신하는 시간을 짧게 줄임
장점: 구현이 쉬움, 가장 적은 시스템 자원 사용 단점: 각 클라이언트의 처리 지연 시간이 길어질 수 있음 각 클라이언트를 스레드를 이용해 독립적으로 처리 장점: 소켓 입출력 모델에 비해 구현이 쉬움 단점: 가장 많은 시스템 자원 사용 소켓 입출력 모델 사용(10~11장) 장점: 소수의 스레드를 이용해 다수의 클라이언트를 처리 ⇒ 상대적으로 적은 시스템 자원 사용 단점: 구현이 어려움

4 TCP 서버-클라이언트의 문제점 (3) 문제 ②: 교착 상태 발생 가능성 TCP 서버 ... recv(...);
send(...); TCP 클라이언트 여기서 대기! (교착 상태)

5 TCP 서버-클라이언트의 문제점 (4) 문제 ② 해결책 데이터 송수신 부분 잘 설계하기 소켓에 타임아웃 옵션 적용하기
장점: 특별한 기법 없이 곧바로 구현 가능 단점: 모든 경우에 대한 해결책은 될 수 없음 소켓에 타임아웃 옵션 적용하기 장점: 구현이 쉬움 단점: 다른 방법에 비해 성능이 낮음 넌블로킹 소켓 사용하기 장점: 근본적으로 교착 상태 해결 단점: 구현이 복잡, 시스템 자원(특히 CPU 시간) 낭비 소켓 입출력 모델 사용(10~11장) 장점: 넌블로킹 소켓의 단점을 보완 & 교착 상태 해결 단점: 첫 번째나 두 번째 해결책보다 구현이 어려움

6 프로세스와 스레드 (1) 용어 프로세스 스레드 주 스레드 or 메인 스레드
코드, 데이터, 리소스를 파일에서 읽어들여 윈도우 운영체제가 할당해놓은 메모리 영역에 담고 있는 일종의 컨테이너로 정적인 개념 스레드 CPU 시간을 할당받아 프로세스 메모리 영역에 있는 코드를 수행하고 데이터를 사용하는 동적인 개념 주 스레드 or 메인 스레드 응용 프로그램 실행 시 최초로 생성되는 스레드 WinMain() 또는 main() 함수에서 실행 시작

7 프로세스와 스레드 (2) 멀티스레드 동작 원리 CPU 스레드① 레지스터 스레드②

8 스레드 생성과 종료 (1) 스레드 생성에 필요한 요소 스레드 함수의 시작 주소 스레드 함수 실행 시 사용할 스택의 크기 f()
{ ... } main() 주 스레드의 실행 스택 스레드①의 코드 스레드②의 주 스레드 스레드①, ②

9 스레드 생성과 종료 (2) CreateThread() 함수 스레드 생성 후 스레드 핸들을 리턴
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

10 스레드 생성과 종료 (3) 스레드 함수 형태 DWORD WINAPI ThreadProc(LPVOID lpParameter) {
... }

11 스레드 생성과 종료 (4) 스레드 종료 방법 ① 스레드 함수가 리턴 ② 스레드 함수 내에서 ExitThread() 함수를 호출
③ 다른 스레드가 TerminateThread() 함수를 호출 ④ 주 스레드가 종료하면 모든 스레드가 종료

12 스레드 생성과 종료 (5) 스레드 종료 함수 void ExitThread ( DWORD dwExitCode // 종료 코드
) ; BOOL TerminateThread ( HANDLE hThread, // 종료할 스레드를 가리키는 핸들 DWORD dwExitCode // 종료 코드 ) ; 성공: 0이 아닌 값, 실패: 0

13 스레드 제어 – 우선순위 변경 (1) 용어 스레드 스케줄링 or CPU 스케줄링 우선순위 클래스 우선순위 레벨 기본 우선순위
프로세스 속성으로, 같은 프로세스가 생성한 스레드는 우선순위 클래스가 모두 같음 우선순위 레벨 스레드 속성으로, 같은 프로세스에 속한 스레드 간 상대적인 우선순위를 결정할 때 사용 기본 우선순위 우선순위 클래스와 우선순위 레벨을 결합한 값으로, 스레드 스케줄링에 사용

14 스레드 제어 – 우선순위 변경 (2) 우선순위 클래스 REALTIME_PRIORITY_CLASS(실시간)
HIGH_PRIORITY_CLASS(높음) ABOVE_NORMAL_PRIORITY_CLASS(높은 우선순위; 윈도우2000 이상) NORMAL_PRIORITY_CLASS(보통) BELOW_NORMAL_PRIORITY_CLASS(낮은 우선순위; 윈도우2000 이상) IDLE_PRIORITY_CLASS(낮음)

15 스레드 제어 – 우선순위 변경 (3) 우선순위 레벨 THREAD_PRIORITY_TIME_CRITICAL
THREAD_PRIORITY_HIGHEST THREAD_PRIORITY_ABOVE_NORMAL THREAD_PRIORITY_NORMAL THREAD_PRIORITY_BELOW_NORMAL THREAD_PRIORITY_LOWEST THREAD_PRIORITY_IDLE

16 스레드 제어 – 우선순위 변경 (4) 윈도우의 스레드 스케줄링 방식 (낮음) 기본 우선순위 (높음) ... 세 개의 스레드를
스케줄러 CPU 스레드 (낮음) 기본 우선순위 (높음) 세 개의 스레드를 번갈아 수행

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

18 스레드 제어 – 스레드 종료 기다리기 (1) WaitForSingleObject() 함수
특정 스레드가 종료할 때까지 기다리기 WaitForSingleObject() 함수 사용 예 DWORD WaitForSingleObject ( HANDLE hHandle, DWORD dwMilliseconds ) ; 성공: WAIT_OBJECT_0 또는 WAIT_TIMEOUT, 실패: WAIT_FAILED HANDLE hThread = CreateThread(...); DWORD retval = WaitForSingleObject(hThread, 1000); if(retval == WAIT_OBJECT_0) { ... } // 스레드 종료 else if(retval == WAIT_TIMEOUT) { ... } // 타임아웃(스레드는 아직 종료 안 함) else { ... } // 에러 발생

19 스레드 제어 – 스레드 종료 기다리기 (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

20 스레드 제어 – 스레드 종료 기다리기 (3) WaitForMultipleObjects() 함수 사용 예 ①
// 모든 스레드의 종료를 기다린다. HANDLE hThread[2]; HANDLE hThread[0] = CreateThread(...); HANDLE hThread[1] = CreateThread(...); WaitForMultipleObjects(2, hThread, TRUE, INFINITE);

21 스레드 제어 – 스레드 종료 기다리기 (4) 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: // 오류 발생 }

22 스레드 제어 – 실행 중지와 재실행 (1) 실행 중지 함수 ① 재실행 함수 DWORD SuspendThread (
HANDLE hThread // 스레드 핸들 ) ; 성공: 중지 횟수, 실패: -1 DWORD ResumeThread ( HANDLE hThread // 스레드 핸들 ) ; 성공: 중지 횟수, 실패: -1

23 스레드 제어 – 실행 중지와 재실행 (2) 실행 중지 함수 ② void Sleep (
DWORD dwMilliseconds // 밀리초(ms) ) ;

24 멀티스레드 TCP 서버 (1) 기본 구조 DWORD WINAPI ProcessClient(LPVOID arg) {
// ③ 전달된 소켓 저장 SOCKET client_sock = (SOCKET)arg; // ④ 클라이언트 정보 얻기 addrlen = sizeof(clientaddr); getpeername(client_sock, (SOCKADDR *)&clientaddr, &addrlen); // ⑤ 클라이언트와 데이터 통신 while(1){ ... }

25 멀티스레드 TCP 서버 (2) 기본 구조(계속) int main(int argc, char *argv[]) { ...
while(1){ // ① 클라이언트 접속 수용 client_sock = accept(listen_sock, ...); // ② 스레드 생성 CreateThread(NULL, 0, ProcessClient, (LPVOID)client_sock, 0, NULL); }

26 멀티스레드 TCP 서버 (3) 소켓과 연관된 주소 정보 얻기 int getpeername ( SOCKET s,
struct sockaddr *name, int *namelen ) ; 성공: 0, 실패: SOCKET_ERROR int getsockname ( SOCKET s, struct sockaddr *name, int *namelen ) ; 성공: 0, 실패: SOCKET_ERROR

27 스레드 동기화 (1) 스레드 동기화 필요성 스레드 1 스레드 2 공유 변수 int money = 1000 ...
① read money into ECX ② ECX = ECX ③ write ECX into money 스레드 2 ② ECX = ECX 공유 변수

28 스레드 동기화 (2) 스레드 동기화 기법 종류 기능 임계 영역 공유 자원에 대해 오직 한 스레드의 접근만 허용
(한 프로세스에 속한 스레드 간에만 사용 가능) 뮤텍스 (서로 다른 프로세스에 속한 스레드 간에도 사용 가능) 이벤트 사건 발생을 알려 대기 중인 스레드를 깨움 세마포어 한정된 개수의 자원에 여러 스레드가 접근할 때, 자원을 사용할 수 있는 스레드 개수를 제한 대기 가능 타이머 정해진 시간이 되면 대기 중인 스레드를 깨움

29 스레드 동기화 (3) 스레드 동기화가 필요한 상황 스레드 동기화 원리 ① 둘 이상의 스레드가 공유 자원에 접근
② 한 스레드가 작업을 완료한 후, 기다리고 있는 다른 스레드에 알림 스레드 동기화 원리 스레드 1 매개체 스레드 2 진행 대기

30 스레드 동기화 (4) (스레드) 동기화 객체의 특징
Create*( ) 함수를 호출하면 커널 메모리 영역에 동기화 객체가 생성되고, 이에 접근할 수 있는 핸들이 리턴됨 평소에는 비신호 상태로 있다가 특정 조건이 만족되면 신호 상태가 됨. 비신호 상태에서 신호 상태로 변화 여부는 Wait*( ) 함수를 사용해 감지(다음 페이지 그림 참조) 사용이 끝나면 CloseHandle( ) 함수를 호출

31 스레드 동기화 (5) 동기화 객체의 상태 변화 동기화 객체 비신호 상태 신호 상태 Wait*() 함수로 감지

32 임계 영역 (1) 임계 영역 둘 이상의 스레드가 공유 자원에 접근할 때, 오직 한 스레드만 접근을 허용해야 하는 경우에 사용 특징 프로세스의 유저 메모리 영역에 존재하는 단순한 구조체이므로 한 프로세스에 속한 스레드 간 동기화에만 사용 일반 동기화 객체보다 빠르고 효율적

33 임계 영역 (2) 임계 영역 사용 예 #include <windows.h> CRITICAL_SECTION cs;
DWORD WINAPI MyThread1(LPVOID arg) { ... EnterCriticalSection(&cs); // 공유 자원 접근 LeaveCriticalSection(&cs); } DWORD WINAPI MyThread2(LPVOID arg)

34 임계 영역 (3) 임계 영역 사용 예(계속) EnterCriticalSection(&cs); // 공유 자원 접근
LeaveCriticalSection(&cs); ... } int main(int argc, char *argv[]) { InitializeCriticalSection(&cs); // 둘 이상의 스레드를 생성하여 작업을 진행한다. // 생성한 모든 스레드가 종료할 때까지 기다린다. DeleteCriticalSection(&cs);

35 이벤트 (1) 이벤트 이벤트를 사용하는 전형적인 절차 사건 발생을 다른 스레드에 알릴 때 사용 ➊ 이벤트를 비신호 상태로 생성
➋ 한 스레드가 작업을 진행하고, 나머지 스레드는 이벤트에 대해 Wait*( ) 함수를 호출해 이벤트가 신호 상태가 될 때까지 대기 ➌ 스레드가 작업을 완료하면 이벤트를 신호 상태로 바꿈 ➍ 기다리고 있던 스레드 중 하나 혹은 전부가 깨어남

36 이벤트 (2) 이벤트 상태 변경 이벤트의 종류 자동 리셋 이벤트 수동 리셋 이벤트
이벤트를 신호 상태로 바꾸면, 기다리는 스레드 중 하나만 깨운 후 자동으로 비신호 상태가 됨 수동 리셋 이벤트 이벤트를 신호 상태로 바꾸면, 기다리는 스레드를 모두 깨운 후 계속 신호 상태를 유지함 BOOL SetEvent(HANDLE hEvent); // 비신호 상태  신호 상태 BOOL ResetEvent(HANDLE hEvent); // 신호 상태  비신호 상태

37 이벤트 (3) 이벤트 생성 HANDLE CreateEvent (
LPSECURITY_ATTRIBUTES lpEventAttributes, BOOL bManualReset, BOOL bInitialState, LPCTSTR lpName ) ; 성공: 이벤트 핸들, 실패: NULL

38 Thank you TCP/IP 윈도우 소켓 프로그래밍


Download ppt "6장. 멀티스레드 멀티스레드 프로그래밍의 필요성을 이해하고 기본 개념을 익힌다."

Similar presentations


Ads by Google