Presentation is loading. Please wait.

Presentation is loading. Please wait.

멀티쓰레드 기반의 서버구현 School of Electronics and Information.

Similar presentations


Presentation on theme: "멀티쓰레드 기반의 서버구현 School of Electronics and Information."— Presentation transcript:

1 멀티쓰레드 기반의 서버구현 School of Electronics and Information.
Kyung Hee University. Dae Sun Kim

2 쓰레드 생성

3 Thread의 개요 Thread란 프로세스와의 차이점 한 프로그램에서 여러 실행 흐름
모든 프로세스는 최소한 하나의 실행 흐름을 가짐 프로세스와의 차이점 스택을 제외한 나머지 메모리 영역을 공유 전역변수, 파일 디스크립터, 시그널 핸들러 그리고 현재 디렉 토리 상태를 스레드 생성자인 프로세스와 공유 일부 메모리를 공유하므로 쓰레드간 통신이 편리 보다 간단한 컨텍스트 스위칭

4 fork 함수 호출을 통한 프로세스의 생성 복사본 프로세스 a=10 a=10 pid=1133 b=20 pid=0 b=20
int a=10; int main() { pid_t pid; int b=20; pid = fork(); ……. } int a=10; int main() { pid_t pid; int b=20; pid = fork(); ……. } a=10 a=10 Data 영역 Data 영역 pid=1133 b=20 Heap 영역 pid=0 b=20 Heap 영역 Stack 영역 Stack 영역 복사본 프로세스 원본 프로세스

5 Process and Thread 실행 흐름 실행 흐름 Thread_1 Thread_2 Process_1 Operating
System Thread_3 Thread_1 Thread_2 Process_2 Thread_3

6 쓰레드 생성 1 #include <pthread.h>
thread : 생선된 쓰레드의 ID를 저장할 변수의 포인터를 인자로 전달 attr : 생성하고자 하는 쓰레드의 특성을 설정할 때 사용(일반적으로 NULL 전달) start_routine : 쓰레드 생성후 실행해야 하는 함수를 가리키는 포인터 arg : 쓰레드에 의해 호출되는 함수에 전달하고자 하는 인자 값 #include <pthread.h> int pthread_create (pthread_t * thread, pthread_attr_t * attr, void*(*start_routine)(void*), void * arg );

7 쓰레드 생성 예제 1 프로그램 예제 (thread1.c) void *thread_function(void *arg);
int main(int argc, char **argv) { int state; pthread_t t_id; state = pthread_create(&t_id, NULL, thread_function, NULL); if(state != 0){ puts("쓰레드 생성 오류"); exit(1); } printf("생성된 쓰레드의 ID : %d \n", t_id); sleep(3); puts("main함수 종료"); return 0; void *thread_function(void *arg) int i; for(i=0; i<3; i++){ sleep(2); puts("쓰레드 실행중");

8 Thread compile -lpthread -D_REENTRANT
Pthread 라이브러리(libpthread.so)를 링크하겠다는 의미 -D_REENTRANT 프로그램 내에서 “#define _REENTRANT” 선언과 같은 효 과 -D_REENTRAN 옵션을 컴파일시에 주면 _REENTRANT가 설정되어 스레드들은 각각 고유한 errono를 갖게 됨 따라서 일반 함수 호출 시에 error 변수나 perror() 함수를 그대로 사용할 수 있음

9 쓰레드 생성 2 pthread_join 함수 인자로 전달되는 ID에 해당하는 쓰레드가 종료될 때까 지 대기 상태에 들어가기 위해서 호출하는 함수 th : th에 인자로 들어오는 ID 쓰레드가 종료할 때까지 실 행을 지연 thread_return : 쓰레드가 종료시 반환하는 값에 접근할 수 있는 2차원 포인터 #include <pthread.h> int pthread_join(pthread_t th, void **thread_return);

10 쓰레드 생성 예제 2 프로그램 예제 (thread2.c)
state = pthread_create(&t_id, NULL, thread_function, NULL); /* 쓰레드 생성 */ if(state != 0){ puts("쓰레드 생성 오류"); exit(1); } printf("생성된 쓰레드의 ID : %d \n", t_id); /* 쓰레드 종료 시까지 main함수의 실행을 지연 */ state = pthread_join(t_id, &t_return); /* 리턴 값 저장 */ if(state != 0){ puts("쓰레드 Join 오류"); printf("main함수 종료, 쓰레드 리턴 %s", (char*)t_return); free(t_return); return 0; } void *thread_function(void *arg) { int i; char * p = (char*)malloc(20*sizeof(char)); strcpy(p, "쓰레드 종료 됨!\n"); for(i=0; i<3; i++){ sleep(2); puts("쓰레드 실행중"); return p;

11 쓰레드 생성 예제 분석 Process Process 생성 thread thread 생성 join 대기상태 리턴 종료 종료 종료
Thread2.c Thread1.c

12 쓰레드 관련 함수 Thread ID 얻기 Thread 종료 #include <pthread.h>
pthread_t pthread_self(void); #include <pthread.h> Void pthread_exit(void *retval)

13 스레드의 취소 1 스레드의 취소 프로그램에서 취소요청 수신 시 이를 즉시 처리 할 수 없는 코드가 실행 중인 경우 반대의 경우
스레드에서 다른 스레드의 실해을 종료시키는 것 다른 스레드를 종료시키기 위해서 취소요청을 전송해 야 함 취소요청을 수신한 스레드는 다음과 같은 상태를 가짐 취소요청 수용 취소요청 무시 프로그램에서 취소요청 수신 시 이를 즉시 처리 할 수 없는 코드가 실행 중인 경우 No cancellation point 반대의 경우 Cancellation point

14 스레드의 취소 2 취소요청을 수용하는 방법 Cancellation point 함수들
read(), write(). open(), close(), fcntl(), sleep(), wait(), waitpid(), pthread_join() and so on 즉 위의 함수가 수행중일 때 취소요청을 수신하면 스레 드는 즉시 취소

15 쓰레드 취소 관련 함수 1 취소요청의 수용여부 설정하는 함수 int state
PHREAD_CANCEL_ENABLE: 취소요청 수용 PHREAD_CANCEL_DISABLE: 취소요청 무시 oldstate: 이전 상태값을 저장. NULL일 경우 이전의 취소 상태 값을 저장 하지않음 성공시 0을 리턴 int phread_setcancelstate(int state, int *oldstate);

16 쓰레드 취소 관련 함수 2 취소요청의 받아들이는 경우 사용되는 함수
취소요청을 받아들인 경우 cancellation point까지 요청을 연기할 것인지 즉시 종료할 것인지 설정 하는 함수 int type PHREAD_CANCEL_ASYNCHRONOUS: 즉시 취소 PHREAD_CANCEL_DEFERRED: cancellation point를 만날 때까지 연기 oldtype: 이전 상태값을 저장. NULL일 경우 이전의 취소 상태 값을 저장 하지않음 성공시 0을 리턴 int phread_ssetcanceltype(int type, int *oldtype);

17 쓰레드 취소 관련 함수 3 cancellation point를 강제로 넣어주는 함수
현재 도착한 취소요청이 있는 지를 검사하고 도착한 취 소요청이 있으면 스레드를 종료시키는 함수 사용예 Code 1은 cancellation point가 없다. Code 2는 100번의 루프 때마다 취소요청이 도착했는지 검사 void pthread_testcancel() Code 2 For( ; ; ) count++; if (count%100=0) pthread_testcancel() Code 1 for( ; ; ) count++;

18 쓰레드 취소 요청을 무시하는 예 // 스레드 시작 함수 void *thrfunc(void *arg) { int status;
curthd = pthread_self(); // 취소요청을 무시하도록 설정 if( (status=pthread_setcancelstate(PTHREAD_CANCEL_DISABLE, NULL))!=0) { printf("pthread_setcancelstate fail: %s\n",strerror(status)); exit(0); } // 무한루프를 돌면서 500,000번째 마다 취소요청을 검사 for(cnt=1; cnt<max_loop; cnt++) if(cnt%50000 == 0) pthread_testcancel(); // 스레드에게 취소요청을 보내고 종료하기를 기다리는 함수 내용 void cancel_and_join(int tid) { void *result; if((status=pthread_cancel(tid)) != 0) { printf("pthread_cancel error : %s\n",strerror(status)); // tid 스레드가 종료하기를 기다림 if((status=pthread_join(tid, &result)) != 0) { printf("pthread join error: %s\n",strerror(status)); // 취소요청에 의해 종료된 경우 PTHREAD_CANCELED이 리턴됨 if(result == PTHREAD_CANCELED) printf("[Thread ID=%d] thread is canceled \n", curthd); else printf("[Thread ID=%d] thread is not canceled\n", curthd); printf("총 %d 번의 루프중 %d 번의 루프를 돌았음\n\n", max_loop, cnt); return ;} 쓰레드 취소 요청을 무시하는 예 파일명: thcancel_dis.c // thread start routine void *thrfunc(void *arg) ; // 취소요청을 보내고 스레드의 종료를 기다리는 함수 void cancel_and_join(int tid); int max_loop= ; int cnt=0; pthread_t curthd; int main(int argc, char **argv) { pthread_t tid; int status, i; struct timespec micro_sec = {0,100000}; // cancel_disable을 테스트 printf("** PTHREAD_CANCEL_DISABLE\n"); if((status=pthread_create(&tid, NULL, &thrfunc, NULL))!=0) { printf("thread create error: %s\n",strerror(status)); exit(0); } // 루프가 도는 도중 취소요청이 도착하도록 sleep nanosleep(&micro_sec, NULL); // 취소요청을 보냄 cancel_and_join(tid); return 0;

19 쓰레드 취소 요청을 무시하는 예의 결과 프로그램 내에서 쓰레드의 취소 환경을 PEREAD_CANCEL_DISABLE로 설정하고 20,000,000번의 루프를 실행 매 500,000 번째마다 pthread_testcancel()를 호출하여 취소요청을 확인 결과는 취소요청이 들어오더라도 이를 무시하도록 설 정하였으므로 모든 루프는 정상적으로 실행 $ thcancel_dis ** PTHREAD_CANCEL_DISABLE [Thread ID=1026] thread is not canceled 총 번의 루프중 번의 루프를 돌았음

20 스레드 취소 요청을 연기하는 예 // 스레드 시작 함수 void *thrfunc(void *arg) { int status;
curthd = pthread_self(); // 취소요청을 무시하도록 설정 if( (status=pthread_setcancelstate(PTHREAD_CANCEL_ENABLE, NULL))!=0) { //취소요청을 cancellation point까지 연기 pthread_setcanceltype(PTHREAD_CANCEL_DEFERRED, NULL); } // 무한루프를 돌면서 500,000번째 마다 취소요청을 검사 for(cnt=1; cnt<max_loop; cnt++) if(cnt%50000 == 0) pthread_testcancel();

21 쓰레드 취소 요청을 연기하는 예의 결과 지연 취소 모드에서 번째 루프에서 스레드가 종료한 것을 알 수 있는데 이 결과로부터 – 루프 수행 도중에 취소요청이 도책했음을 알 수 있다. $ thcancel_def ** PTHREAD_CANCEL_ENABLE [Thread ID=1026] thread is canceled 총 번의 루프중 번의 루프를 돌았음

22 스레드 취소 요청을 즉시 취소하는 예 // 스레드 시작 함수 void *thrfunc(void *arg) {
int status; curthd = pthread_self(); // 취소요청을 무시하도록 설정 if( (status=pthread_setcancelstate(PTHREAD_CANCEL_ENABLE, NULL))!=0) { //취소요청을 cancellation point까지 연기 pthread_setcanceltype(PTHREAD_CANCEL_ASYNCHR, NULL); } // 무한루프를 돌면서 500,000번째 마다 취소요청을 검사 for(cnt=1; cnt<max_loop; cnt++) if(cnt%50000 == 0) pthread_testcancel();

23 쓰레드 취소 요청을 즉시 취소하는 결과 즉시 취소 모드에서 771136번의 루프를 실행하고 종 료 됨
즉시 취소 모드에서 취소요청이 도착하자마자 바로 스레드가 종료되므로 번째 루프 실행시에 취 소요청이 도착했음을 알 수 있다 $ thcancel_async ** PTHREAD_CANCEL_ENABLE [Thread ID=1026] thread is canceled 총 번의 루프중 번의 루프를 돌았음

24 멀티 쓰레드 예제 확인 void *thread_summation(void *arg); int sum=0;
int main(int argc, char **argv) { pthread_t id_t1, id_t2; void * t_return; pthread_create(&id_t1, NULL, thread_summation, (void *)sum1); pthread_create(&id_t2, NULL, thread_summation, (void *)sum2); /* 쓰레드 종료 시까지 main함수의 실행을 지연 */ pthread_join(id_t1, &t_return); pthread_join(id_t2, &t_return); printf("main함수 종료, sum = %d \n", sum); return 0; } void *thread_summation(void *arg) int start = ((int*)arg)[0]; int end = ((int*)arg)[1]; for( ; start<=end; start++) sum+=start; } //thread3.c #define NUMBER 10000 void *thread_increment(void *arg); int num=0; int main(int argc, char **argv) { int i; pthread_t thread_id[10]; void * t_return; for(i=0; i<10; i++) pthread_create(&thread_id[i], NULL, thread_increment, NULL); /* 생성한 모든 쓰레드 종료 시까지 main함수의 실행을 지연 */ pthread_join(thread_id[i], &t_return); printf("main함수 종료, num=%d \n", num); return 0; } void *thread_increment(void *arg) for(i=0 ; i<NUMBER; i++) num++; } //thread3.c

25 스레드의 동기화 문제 한 스레드가 공유 데이터를 액세스하는 도중 다른 스레드가 이 공유 데이터를 액세스하게 되면 그 데 이터의 값을 정확히 예측 할 수 없음 이러한 문제를 동기화 문제라고 함 임계영역 두개 이상의 쓰레드에 의해서 동시에 실행되면 안 되는 영역.

26 두개의 쓰레드에 의한 덧셈 연산 . i = 10 . i = 20 10 + 10 =20 10 + 10 20 [2단계]
1. 서비스 시작 5. 서비스 시작 3. 서비스 일시 종료 8. 서비스 시작 7. 결과값 리턴 6. 임시저장 후 덧샘 연산 2. 임시 저장 후 덧샘 연산 9. 결과 값 리턴 =20 4. 덧샘 결과 20을 임시 저장 20 [2단계] int i = 10 i+=10

27 동기화(Synchronization)
임계영역 둘 이상의 쓰레드에 의해서 공유되는 메모리 공간에 접 근하는 코드영역. 동기화. 첫째 : 공유된 메모리에 둘 이상의 쓰레드가 동시 접근 하는 것을 막는 행위 둘째 : 둘 이상의 쓰레드 실행순서를 컨트롤(control)하는 행위. 대표적인 동기화 기법. 뮤텍스, 세마포어

28 뮤텍스 뮤텍스 기본 원리 뮤텍스를 조작하는 함수들 pthread_mutex_t 타입의 변수를 가리켜 뮤텍스라고 표현한다.
일종의 문고리에 해당한다. 기본 원리 임계영역에 들어 갈 때 뮤텍스(문고리)를 잠그고 들어간다. 임계영역에서 빠져 나올 때 뮤텍스를 풀고 나간다. 뮤텍스를 조작하는 함수들 뮤텍스 초기화 함수 : pthread_mutex_init 뮤텍스 소멸 함수 : pthread_mutex_destroy 뮤텍스 잠그는 함수 : pthread_mutex_lock 뮤텍스 풀어주는 함수 : pthread_mutex_unlock

29 뮤텍스의 동기화 원리

30 프로그램 예제 프로그램 예제 mutex.c 실행결과.

31 세마포어 세마포어 기본 원리 세마포어를 조작하는 함수들 sem_t 타입의 변수를 가리켜 흔히 세마포어라 표현한다.
세마포어는 정수를 지닌다. 정수의 값이 0이면 실행 불가를 의미한다. 세마포어가 1이상이 되면 실행 가능을 의미한다. 세마포어는 0미만이 될 수 없지만 1이상은 될 수 있다 0과 1의 상태만을 지니는 세마포어를 가리켜 바이너리 세마포어라 한다. 세마포어를 조작하는 함수들 세마포어 초기화 함수 : sem_init 세마포어 소멸 함수 : sem_destroy 세마포어 감소 함수 : sem_wait 세마포어 증가 함수 : sem_post

32 세마포어 조작 함수 sem_init : 세마포어를 초기화하는 함수. sem : 초기화하고자 하는 세마포어 변수의 포인터
pshared : 0-> 하나의 프로세스 내에서만 사용, ‘0’이외의 값은 여러개의 프로세스가 공유할 수 있는 세마포어 생 성 value : 초기화 하고자 하는 값 #include<semaphore.h> int sem_init(sem_t *sem, int pshared, unsigned int value); int sem_wait(sem_t * sem); int sem_post(sem_t * sem); int sem_destroy(sem_t * sem);

33 세마포어 동기화 원리

34 프로그램 예제 확인 프로그램 예제 semaphore.c 실행결과.

35 실습과제 chat_server.c 와 chat_client.c 분석후(메모장 이용) 제 출 쓰레드 기반의 서버
뮤텍스를 이용하여 동기화


Download ppt "멀티쓰레드 기반의 서버구현 School of Electronics and Information."

Similar presentations


Ads by Google