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

Slides:



Advertisements
Similar presentations
POSIX thread SSLab. 신장열. CONTENTS Thread 의 생성 및 종료 Join and detach Cleanup handler Mutex Condition variable Thread signal Thread cancel.
Advertisements

스택 스택 추상자료형 스택 스택의 구현 스택의 응용 한빛미디어(주).
프로그래밍1 및 실습 (C언어) - 3장 기본자료형 (3.6부터 끝까지) -
제 3 장 변수와 자료형.
Linux/UNIX Programming APUE (The Environment of a UNIX Process)
쉽게 풀어쓴 C언어 Express 제11장 포인터 C Express.
제 8 장  파서 생성기 YACC 사용하기.
C 프로그래밍.
Linux System Programming
Department of Computer Engineering
인공지능실험실 석사 2학기 김승겸 TCP/IP Socket Programming… 제 10장 멀티태스킹 기반의 서버구현 인공지능실험실 석사 2학기 김승겸
Signal & Inter-Process Communication
공유 메모리[1] 공유 메모리 공유 메모리 생성: shmget(2) 같은 메모리 공간을 두 개 이상의 프로세스가 공유하는 것
디바이스 드라이버 기초 디바이스 드라이버의 개요 파일 연산 디바이스 드라이버 등록 디바이스 드라이버 구성
디바이스 드라이버 개요 가상 디바이스드라이버 실습
제3장 추가 실습 3장 관련 C 언어 프로그래밍 실습.
Department of Computer Engineering
쉽게 풀어쓴 C언어 Express 제17장 동적 메모리와 연결 리스트 C Express.
쉽게 풀어쓴 C언어 Express 제4장 변수와 자료형 C Express.
Multi-thread Programming
C언어: 배열 (Arrays).
6 프로세스 생성과 실행.
배열, 포인터, 참조 배열은 같은 형을 가지는 변수들의 묶음이다..
Linux System Programming
인터넷 주소 변환 School of Electronics and Information. Kyung Hee University.
제 12장 I/O멀티플렉싱(Multiplexing)
10장 메모리 관리.
쉽게 풀어쓴 C언어 Express 제17장 동적 메모리와 연결 리스트 C Express.
쉽게 풀어쓴 C언어 Express 제17장 동적메모리와 연결리스트 C Express.
Department of Computer Engineering
동적메모리와 연결리스트 컴퓨터시뮬레이션학과 2016년 봄학기 담당교수 : 이형원 E304호,
데이터베이스 실험실 석사 2학기 김기훈 TCP/IP Socket Programming… 제 17장 멀티쓰레드 기반의 서버구현 데이터베이스 실험실 석사 2학기 김기훈
Department of Computer Engineering
fork로 생성한 자식 프로세스에서 exec 함수군을 호출
Multi-thread Programming
Multi-thread Programming
운영체제 허상복 컴퓨터시스템 연구실
Department of Computer Engineering
쉽게 풀어쓴 C언어 Express 제14장 포인터 활용 C Express.
Multi-thread Programming
Term Project Team Member
Homework 6… 12월 2일(금) 11:59pm까지 자신의 이름과 학번을 출력해 주는 유닉스/리눅스 네트워크 소켓 서버 프로그램 과 클라이언트 프로그램 을 작성해 보세요 참고 (실습1) Hello 프로그램 helloserver.c helloclient.c 컴파일.
Advanced Socket Programming
(ioctl, mmap, fsync&flush)
Department of Computer Engineering
제 3 장 상수와 변수
10장 C 표준 파일 입출력 子曰 學而時習(실습?)之 不亦悅乎.
소켓의 옵션 School of Electronics and Information. Kyung Hee University.
텀 프로젝트 보고서 - 7조 – 제목 : 자동 빨래 건조기
Signal & Inter-Process Communication
자전거를 배우려면 안장에 올라가 페달을 밟아라.
네트워크 프로그래밍의 이해 School of Electronics and Information.
함수와 변수 컴퓨터시뮬레이션학과 2016년 봄학기 담당교수 : 이형원 E304호,
데이터베이스실험실 석사 2학기 조정희 TCP/IP Socket Programming… 제 19장 윈도우 기반의 쓰레드 동기화 데이터베이스실험실 석사 2학기 조정희
발표자료는 다음링크에서 다운로드 받으실 수 있습니다.
Linux/UNIX Programming APUE (Thread Programming)
데이터베이스실험실 석사 2학기 조정희 TCP/IP Socket Programming… 제 18장 윈도우 기반 쓰레드 사용하기 데이터베이스실험실 석사 2학기 조정희
Operating System Multiple Access Chatting Program using Multithread
Signal & Inter-Process Communication
C89(C++03) 프로그래밍 (Part 2) 7 배열 8 변수 범위 9 포인터 10 유도 자료형.
Department of Computer Engineering
Multi-thread Programming
자료구조 세미나 발표 주제: 자료구조 기초 - 1회 차: 자료구조의 정의, 기초 지식 (함수, 포인터, 레퍼런스)
컴퓨터 프로그래밍 기초 - 11th : 파일 입출력 및 구조체 -
실습과제 1번 생성된 파일 basic.txt를 프로젝트 폴더에서 메모장으로 열고 내용을 확인
대림대학교 2017년도 1학기 강의 왕보현 순서도와 스크래치 6주차 대림대학교 2017년도 1학기 강의 왕보현
9장. C 언어의 핵심! 함수. 9장. C 언어의 핵심! 함수 9-1 함수의 정의와 선언 main 함수 다시 보기 : 함수의 기본 형태 { } 그림 9-1.
argc, argv 의 사용방법 #include <stdio.h>
Signal & Inter-Process Communication
C.
Presentation transcript:

멀티쓰레드 기반의 서버구현 School of Electronics and Information. Kyung Hee University. Dae Sun Kim <dskim@networking.khu.ac.kr>

쓰레드 생성

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

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 영역 복사본 프로세스 원본 프로세스

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

쓰레드 생성 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 );

쓰레드 생성 예제 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("쓰레드 실행중");

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

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

쓰레드 생성 예제 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;

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

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

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

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

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

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

쓰레드 취소 관련 함수 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++;

쓰레드 취소 요청을 무시하는 예 // 스레드 시작 함수 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=20000000; 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;

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

스레드 취소 요청을 연기하는 예 // 스레드 시작 함수 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();

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

스레드 취소 요청을 즉시 취소하는 예 // 스레드 시작 함수 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();

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

멀티 쓰레드 예제 확인 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

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

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

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

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

뮤텍스의 동기화 원리

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

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

세마포어 조작 함수 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);

세마포어 동기화 원리

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

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