데이터베이스실험실 석사 2학기 조정희 jjh1977@dblab.hannam.ac.kr TCP/IP Socket Programming… 제 19장 윈도우 기반의 쓰레드 동기화 데이터베이스실험실 석사 2학기 조정희 jjh1977@dblab.hannam.ac.kr.

Slides:



Advertisements
Similar presentations
C 프로그래밍 기초.
Advertisements

Vision System Lab, Sang-Hun Han
제12장 표준 입출력과 파일 입출력.
Linux/UNIX Programming APUE (The Environment of a UNIX Process)
슬라이드 1~21까지는 각자 복습! 슬라이드 22부터는 수업시간에 복습
2016 ITA 1월 강의 C Programming -4일차- 포인터배열 및 이중포인터 정대진 ( )
C++ Espresso 제1장 기초 사항.
6장. 멀티스레드 멀티스레드 프로그래밍의 필요성을 이해하고 기본 개념을 익힌다.
쉽게 풀어쓴 C언어 Express 제11장 포인터 C Express.
제 6장 프로세스 간 동기화 및 통신 6.1 개요 6.2 병행 처리의 문제점
-Part3- 제3장 콘솔 입출력과 파일 입출력.
C 프로그래밍 소개 숙명여대 창병모 2011 가을.
Chapter 10– 표준 함수(1) Outline 10.1 스트림과 파일 10.2 입출력 표준 함수
제 8 장  파서 생성기 YACC 사용하기.
Department of Computer Engineering
인공지능실험실 석사 2학기 김승겸 TCP/IP Socket Programming… 제 10장 멀티태스킹 기반의 서버구현 인공지능실험실 석사 2학기 김승겸
C 6장. 함수 #include <stdio.h> int main(void) { int num;
Department of Computer Engineering
쉽게 풀어쓴 C언어 Express 제18장 입출력과 라이브러리 함수 C Express.
4장: 자료형과 수식.
Multi-thread Programming
C언어: 배열 (Arrays).
컴퓨터의 기초 제 4강 - 표준 입출력, 함수의 기초 2006년 4월 10일.
스레드의 개념과 동작 원리를 이해한다. MFC 스레드의 두 종류인 작업자 스레드와 UI 스레드 사용법을 익힌다.
Ch 14. System Thread.
MultiThread.
Network Lab. Seoung Hyeon, Lee
6 프로세스 생성과 실행.
버퍼 오버플로우에 대한 대책과 발전된 공격 안전한 함수 사용 버퍼 오버플로우에 취약한 함수 사용하지 않기
Chapter 11. Raw 소켓.
Linux System Programming
쉽게 풀어쓴 C언어 Express 제16장 파일 입출력 C Express Slide 1 (of 23)
HW#1 Source 파일 제출 3.20(수)까지 제출 학번_이름_01.c
Part 14 파일 입출력 ©우균, 창병모 ©우균, 창병모.
제 12장 I/O멀티플렉싱(Multiplexing)
연산자 대입 연산자 산술 연산자 관계 연산자 논리 연산자 비트 연산자 콤마 연산자 축약 연산자 sizeof 연산자
Department of Computer Engineering
데이터베이스 실험실 석사 2학기 김기훈 TCP/IP Socket Programming… 제 17장 멀티쓰레드 기반의 서버구현 데이터베이스 실험실 석사 2학기 김기훈
Department of Computer Engineering
멀티쓰레드 기반의 서버구현 School of Electronics and Information.
운영체제 허상복 컴퓨터시스템 연구실
21장. 문자와 문자열 처리 함수.
9장 파일 입출력.
쉽게 풀어쓴 C언어 Express 제14장 포인터 활용 C Express.
Term Project Team Member
처음으로 배우는 C 프로그래밍 제5부 추가적인 화제들 제 11 장 파일 처리.
제 2 장 변수와 상수.
Department of Computer Engineering
Chapter 13 변수 범위.
제 3 장 상수와 변수
10장 C 표준 파일 입출력 子曰 學而時習(실습?)之 不亦悅乎.
날짜: 팀명: TEAM-SIX 발표자: 이기영
4장 제어문 선택문: if 문, if – else 문, switch 문
18강 파일처리함수(2) 강 의 내 용 순차파일 만들기와 읽기 순차파일 입출력함수 랜덤파일 처리
4주차: Data Types and Functions
2장 표준 입출력 표준 입출력 함수의 종류 형식화된 입출력 문자 입출력 문자열 입출력.
멀티스레드 Chapter 05. * 학습목표 멀티스레드의 필요성을 이해하고 기본 개념을 익힘.
컴퓨터의 기초 제 2강 - 변수와 자료형 , 연산자 2006년 3월 27일.
제 3 장 연산자 (Operators).
데이터베이스실험실 석사 2학기 조정희 TCP/IP Socket Programming… 제 18장 윈도우 기반 쓰레드 사용하기 데이터베이스실험실 석사 2학기 조정희
3장. 변수와 연산자. 3장. 변수와 연산자 3-1 연산자, 덧셈 연산자 연산자란 무엇인가? 연산을 요구할 때 사용되는 기호 ex : +, -, *, / 3-1 연산자, 덧셈 연산자 연산자란 무엇인가? 연산을 요구할 때 사용되는 기호 ex : +, -, *, /
6장 반복제어문 for 문 while 문 do while 문 기타 제어문.
Department of Computer Engineering
실습과제 1번 생성된 파일 basic.txt를 프로젝트 폴더에서 메모장으로 열고 내용을 확인
3주차: Control Flow and Others
argc, argv 의 사용방법 #include <stdio.h>
C 13장. 입출력 라이브러리 #include <stdio.h> int main(void) { int num;
C.
개정판 누구나 즐기는 C언어 콘서트 제12장 파일 입출력 출처: pixabay.
⊙ 입출력 처리란? data를 입력장치로부터 program 내부로 읽어 들이거나
Presentation transcript:

데이터베이스실험실 석사 2학기 조정희 jjh1977@dblab.hannam.ac.kr TCP/IP Socket Programming… 제 19장 윈도우 기반의 쓰레드 동기화 데이터베이스실험실 석사 2학기 조정희 jjh1977@dblab.hannam.ac.kr

목차 쓰레드 동기화 기법의 분류 CRITICAL_SECTION Mutex(Mutual Exclusion) Semaphore Event

쓰레드 동기화 기법의 분류 [1] 프로세스 실행의 두 가지 모드 유저 모드란? 커널 모드란? 유저 모드(User Mode)와 커널 모드(Kernel Mode) 시스템의 안정성을 보장하기 위해서 제공 유저 모드란? 일반적인 프로그램의 실행 모드 시스템 리소스로의 접근이 허용되지 않음 유저 모드 동기화 기법 CRITICAL_SECTION 오브젝트의 사용 커널 모드란? 시스템 리소스로의 접근을 위한 프로세스의 실행 모드 커널 오브젝트를 통한 시스템 리소스(File, Thread 등등)의 접근 시 유저모드에서 커널 모드로의 변환이 발생 커널 모드 동기화 기법 Event, Semaphore, Mutex 커널 오브젝트의 사용

쓰레드 동기화 기법의 분류 [2] 두 가지 모드 동기화의 장단점 유저 모드 동기화의 장단점 커널 모드 동기화의 장단점 장점 : 프로그래밍 하기 수월하며 속도가 빠름 단점 : 커널 모드 동기화 기법에 비해서 제한된 기능을 가짐 커널 모드 동기화의 장단점 장점 : Deadlock 문제를 막을 수 있음(단, 해결책이 되는 것음 아님) 둘 이상의 프로세스 내에 존재하는 쓰레드 간의 동기화 가능 단점 : 실행 속도의 저하가 발생

CRITICAL_SECTION [1] 유저모드 동기화 기법 동기화 관련 함수 void InitializeCriticalSection( LPCRITICAL_SECTION lpCriticalSection); lpCriticalSection : 초기화할 CRITICAL_SECTION 변수의 포인터를 전달 void EnterCriticalSection( LPCRITICAL_SECTION lpCriticalSection); lpCriticalSection : 소유하고자 하는 CS의 포인터를 전달 만약 다른 쓰레드에 의해 소유된 상태라면 대기 상태로 들어감 이전에 소유했던 쓰레드가 임계 영역을 빠져 나오면서 CS를 반환하게 되면 대기 상태의 쓰레드는 CS를 얻게 됨과 동시에 임계 영역에 들어감 void LeaveCriticalSection( LPCRITICAL_SECTION lpCriticalSection); lpCriticalSection : 반환하고자 하는 CS의 포인터를 전달 void DeleteCriticalSection( LPCRITICAL_SECTION lpCriticalSection); lpCriticalSection : 소멸하고자 하는 CS의 포인터를 전달

CRITICAL_SECTION [2] 동기화 예제 int sum=0; int sum1[]={1, 5}; CRITICAL_SECTION cs; int main(int argc, char **argv) { HANDLE hThread1, hThread2; DWORD dwThreadID1, dwThreadID2; InitializeCriticalSection(&cs); hThread1 = (HANDLE)_beginthreadex(NULL, 0, ThreadSummation, (void*)sum1, 0, (unsigned *)&dwThreadID1); hThread2 = (HANDLE)_beginthreadex(NULL, 0, ThreadSummation, (void*)sum2, 0, (unsigned *)&dwThreadID2); if(hThread1==0 || hThread2==0) ErrorHandling("쓰레드 생성 오류"); if(WaitForSingleObject(hThread1, INFINITE)==WAIT_FAILED) ErrorHandling("쓰레드 wait 오류"); if(WaitForSingleObject(hThread2, INFINITE)==WAIT_FAILED) printf("main함수 종료, sum = %d \n", sum); DeleteCriticalSection(&cs); return 0; } DWORD WINAPI ThreadSummation(void *arg) { int start=((int*)arg)[0]; int end=((int*)arg)[1]; for( ; start<=end; start++) { EnterCriticalSection(&cs); sum+=start; LeaveCriticalSection(&cs); } return 0; void ErrorHandling(char *message) fputs(message, stderr); fputc('\n', stderr); exit(1);

CRITICAL_SECTION [3] 예제 실행 결과

커널 오브젝트의 상태 Mutex 기준 Semaphore 기준 signaled 상태 – 소유가 가능한 상태 non-signaled 상태 – 이미 소유되어진 상태 Semaphore 기준 signaled 상태 – 세마포어 카운트가 0이 아닌 경우 Non-signaled 상태 – 세마포어 카운트가 0인 경우

Mutex [1] Mutex 생성 함수 Mutex 소유 함수 WaitForSingleObject 함수 HANDLE CreateMutex( LPSECURITY_ATTRIBUTES lpMutexAttributes, // SD BOOL bInitialOwner, // initial owner(false for signaled) LPCTSTR lpName // object name ); lpMutexAttributes : 보안 관련 특성 전달(NULL) bInitialOwner : TRUE가 전달되는 경우는 생성된 Mutex의 소유자가 함수를 호출한 쓰레드를 초기화 FALSE가 전달되는 경우 Mutex의 소유자가 존재하지 않음 – Mutex는 signaled 상태 lpName : 생성되는 Mutex에 이름을 줄 경우 사용되는 인자(NULL – 이름 없는 Mutex를 생성)

Mutex [2] Mutex 반환 함수 Mutex 소멸 함수 BOOL ReleaseMutex( HANDLE hMutex // non-signaled -> signaled ); hMutex : 반환하고자 하는 Mutex를 인자로 전달 실제로는 Mutex의 상태를 non-signaled에서 signaled 상태로 바꾸는 함수 BOOL CloseHandle( HANDLE hObject); // handle to object hObject : 소멸하고자 하는 커널 오브젝트의 핸들을 전달

Mutex [3] Mutex의 동작 Signaled Non-Signaled Mutex 생성 상태 전환 A-1. WaitForSingleObject 호출 후 진입 A-2. ReleaseMutex 호출 후 탈출 B-1. WaitForSingleObject 호출 후 대기 임계 영역

Mutex [4] Mutex 예제 int number=0; HANDLE hMutex; int main(int argc, char **argv) { HANDLE hThread1, hThread2; DWORD dwThreadID1, dwThreadID2; hMutex = CreateMutex(NULL, FALSE, NULL); if(hMutex==NULL){ puts("뮤텍스 오브젝트 생성 실패"); exit(1); } hThread1 = (HANDLE)_beginthreadex(NULL, 0, ThreadIncrement, (void*)thread1, 0, (unsigned *)&dwThreadID1); hThread2 = (HANDLE)_beginthreadex(NULL, 0, ThreadIncrement, (void*)thread2, 0, (unsigned *)&dwThreadID2); if(hThread1==0 || hThread2==0) { puts("쓰레드 생성 오류"); if(WaitForSingleObject(hThread1, INFINITE)==WAIT_FAILED) ErrorHandling("쓰레드 wait 오류"); if(WaitForSingleObject(hThread2, INFINITE)==WAIT_FAILED) printf("최종 number : %d \n", number); CloseHandle(hMutex); //Mutex 오브젝트 소멸 return 0; } DWORD WINAPI ThreadIncrement(void *arg) { int i; for(i=0; i<5; i++) { WaitForSingleObject(hMutex, INFINITE); //Mutex를 얻는다. Sleep(100); number++; printf("실행 : %s, number : %d \n", (char*)arg, number); ReleaseMutex(hMutex);// Mutex를 반환한다. void ErrorHandling(char *message) fputs(message, stderr); fputc('\n', stderr); exit(1);

Mutex [5] 예제 실행 결과

Semaphore [1] Semaphore의 특징 Semaphore 생성 함수 세마포어가 0이 되어야 세마포어 오브젝트가 non-signaled 상태가 됨 Semaphore 생성 함수 HANDLE CreateSemaphore( LPSECURITY_ATTRIBUTES lpSemaphoreAttributes, // SD LONG lInitialCount, // initial count LONG lMaximumCount, // maximum count LPCTSTR lpName // object name ); lpSemaphoreAttributes : Mutex와 마찬가지로 Null lInitialCount : Semaphore의 생성 시 초기 값(count 값)을 설정 0이상이고 lMaximumCount에 전달되는 값보다 같거나 적어야 함 0인 경우 non-signaled 상태이고 0보다 큰 경우 signaled 상태 1인경우 Semaphore 얻을 수 있는 상태이고 0인 경우 Semaphore가 누군가에게 소유된 상태 lMaximumCount : 최대 카운트 값 결정 1을 최대값으로 설정하면 바이너리 Semaphore lpName : 생성되는 Semaphore에 이름을 줄 경우 사용되는 인자

Semaphore [2] Semaphore 반환 함수 BOOL ReleaseSemaphore( HANDLE hSemaphore, // handle to semaphore LONG lReleaseCount, // count increment amount LPLONG lpPreviousCount // previous count ); hSemaphore : 반환하고자 하는 Semaphore의 핸들을 전달 lReleaseCount : 반환한다는 것은 카운트의 증가를 의미 일반적으로 1을 전달 최대 카운트(Semaphore 생성 시 결정)를 넘겨서 증가시킬 것을 요구하는 경우 카운트 변경없이 FALSE만 리턴 lpPreviousCount : ReleaseSemaphore 함수 호출로 변경되기 전의 카운트 값을 저장할 변수의 포인터 전달 필요 없다면 NULL 포인터 전달

Semaphore [3] Semaphore 예제 hSem=CreateSemaphore(NULL, 0, 1, NULL); // 바이너리 세마포어 생성. hSem2=CreateSemaphore(NULL, 0, 1, NULL); DWORD WINAPI ThreadSend(void * arg) { int i; for(i=0; i<4; i++){ number++; printf("실행 : %s, number : %d \n", (char*)arg, number); ReleaseSemaphore(hSem, 1, NULL); // hSem 세마포어 1 증가! WaitForSingleObject(hSem2, INFINITE); // hSem2 세마포어 1 감소! } return 0; DWORD WINAPI ThreadRecv(void * arg) for(i=0; i<2; i++){ WaitForSingleObject(hSem, INFINITE); // hSem 세마포어 1 감소! number--; printf("실행 : %s, number : %d \n", (char*)arg, number); ReleaseSemaphore(hSem2, 1, NULL); // hSem2 세마포어 1 증가!

Semaphore [4] 예제 실행 결과

Event [1] Event의 특징 Event 생성 함수 auto & manual-reset 모드의 커널 오브젝트의 생성이 가능 Event 생성 함수 HANDLE CreateEvent( LPSECURITY_ATTRIBUTES lpEventAttributes, // SD BOOL bManualReset, // reset type, TRUE for manual-reset BOOL bInitialState, // initial state, TRUE for signaled state LPCTSTR lpName // object name ); lpEvntArrtibutes : NULL 포인터 전달 bManualReset : CreateEvent 함수의 가장 중요한 전달 인자 manual-reset 모드 Event를 생성하느냐 auto-reset Event를 생성하느냐를 결정 TRUE 전달할 경우 manual-reset 모드의 Event 생성 – Event가 signaled 상태에 있을 경우 ResetEvent 함수를 호출하지 않는 이상 non-signaled 상태로 돌아가지 않음을 의미 FALSE 전달할 경우 auto-reset 모드 Event 생성 – WaitForSingleObject 함수 호출이 성공적으로 끝나는 경우 알아서 non-signaled로 변경을 의미 bInitialState : TRUE인 경우 signaled 상태의 Event 생성, FALSE인 경우 non-signaled Event 생성 lpName : 생성되는 Event에 이름을 줄 경우 사용하는 인자

Event [2] manual-reset 모드 Event 동기화 원리 대기 상태의 쓰레드 Manual Reset Event Main thread Non-signaled thread 1. ResetEvent 2. Signaled 상태로… 3. 모두 깨운다! Manual Reset Event 대기 상태의 쓰레드

Event [3] Event 예제 DWORD WINAPI NumberOfA(void *arg) { int i; int count=0; WaitForSingleObject(hEvent, INFINITE); //Event를 얻는다. for(i=0; String[i]!=0; i++) { if(String[i]=='A') count++; } printf("A 문자의 수 : %d\n", count); return 0; DWORD WINAPI NumberOfOthers(void *arg) if(String[i]!='A') printf("A 이외의 문자 수 : %d\n", count-1); void ErrorHandling(char *message) fputs(message, stderr); fputc('\n', stderr); exit(1); hThread1 = (HANDLE)_beginthreadex(NULL, 0, NumberOfA, NULL, 0, (unsigned *)&dwThreadID1); hThread2 = (HANDLE)_beginthreadex(NULL, 0, NumberOfOthers, NULL, 0, (unsigned *)&dwThreadID2); if(hThread1==0 || hThread2==0) { puts("쓰레드 생성 오류"); exit(1); } fputs("문자열을 입력 하세요 : ", stdout); fgets(String, 30, stdin); SetEvent(hEvent); // Event 오브젝트를 signaled 상태로 변경 if(WaitForSingleObject(hThread1, INFINITE)==WAIT_FAILED) ErrorHandling("쓰레드 wait 오류"); if(WaitForSingleObject(hThread2, INFINITE)==WAIT_FAILED) CloseHandle(hEvent); //Event 오브젝트 소멸 return 0;

Event [4] Event 예제 실행 결과

참고문헌 “TCP/IP 소켓 프로그래밍”, 윤성우 저

Q & A