Download presentation
Presentation is loading. Please wait.
Published byFrédéric Rondeau Modified 6년 전
1
데이터베이스 실험실 석사 2학기 김기훈 Khkim@dblab.hannam.ac.kr
TCP/IP Socket Programming… 제 17장 멀티쓰레드 기반의 서버구현 데이터베이스 실험실 석사 2학기 김기훈
2
목차 쓰레드란 무엇인가 쓰레드 생성하기 다중 쓰레드 생성하기 임계영역 & 쓰레드의 문제점 뮤텍스(mutex)
세마포어(Semaphore) 쓰레드 기반 서버 구현
3
쓰레드란 무엇인가[1] 경량화 된 프로세스 프로세스와의 차이점 프로세스와 마찬가지로 동시실행이 가능함
프로세스의 단점을 극복하기 위해 등장 프로세스와의 차이점 스텍을 제외한 나머지 메모리 공간을 공유 보다 간단한 컨텍스트 스위칭(context switching) 일부메모리를 공유하므로 스레드간 통신이 편리 Process Process Global Variables Global Variables Heap Heap Thread Stack Thread Stack Thread Stack Thread Stack Thread Thread 1 Thread 1 Thread 1
4
쓰레드란 무엇인가[2] 프로세스와 쓰레드
5
쓰레드 생성하기[1] 쓰레드를 생성하는 함수 Pthread_create 함수
thread : 생성된 쓰레드의 ID를 저장할 변수의 포인터를 인자로 전달 Attr : 생성하고자 하는 쓰레드의 특성(attribute)을 설정할 때 사용, 일반적으로 Null을 전달 Start_routine : 리턴타입과 인자가 void*인 함수를 가르키는 포인터 Arg : 쓰레드에 의해 호출되는 함수에 전달하고자 하는 인자값을 넘겨줌 #include <pthread.h> int pthread_create (pthead_t * thread, pthread_attr-t * attr, void * (* start_routine) (void *), void * arg ); 성공 시 0, 실패 시 이외의 값 리턴
6
쓰레드 생성하기[2] thread1.c Process Thread 실행결과
void *thread_function(void *arg); int main(int argc, char **argv){ int state; pthread_t t_id; void *t_return; 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("쓰레드 실행 중"); Process Thread 쓰레드 생성 종료
7
쓰레드 생성하기[3] pthread_join 함수 th : th에 인자로 들어오는 ID의 쓰레드가 종료할 때까지 실행 지연
thread_return : 쓰레드가 종료 시 반환하는 값에 접근할 수 있는 2차원포인터 #include <pthread.h> int pthread_join(pthead_t * th, void **thread_return); ); 성공 시 0, 실패 시 이외의 값 리턴
8
쓰레드 생성하기[4] thread2.c Process Thread 실행결과
int main(int argc, char **argv){ . . . void *t_return; state = pthread_create(&t_id, NULL, thread_function, NULL); printf("생성된 쓰레드 ID : %d \n", t_id); /* 쓰레드 종료 시까지 main함수의 실행을 지연 */ state = pthread_join(t_id, &t_return); /* 리턴 값 저장 */ if(state !=0 ){ puts("쓰레드 Join 오류"); exit(1); } 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 Thread 쓰레드 생성 종료 JOIN RETURN 대기상태
9
다중 쓰레드 생성하기[1] 임계영역(Critical Section)과 쓰레드에 안전한 함수의 호출 임계영역
두개 이상의 쓰레드에 의해서 동시에 실행되면 안 되는 영역 쓰레드 관점에서 볼 때 함수의 종류 쓰레드 불안전한 함수(Thread-unsafe Function) 단일 쓰레드 모델에서는 사용 가능함 함수이지만 다중 쓰레드 모델에서는 사용할 수 없는 함수(gethostbyname) 쓰레드 안전한 함수(Thread-safe Function) 다중 쓰레드 모델에서 사용 가능한 함수(gethostbyname_r) 불안전한 함수를 안전한 함수로 변경 컴파일시 –D_REENTRANT를 옵션으로 넣어 주는 방식으로 매크로를 선언
10
다중 쓰레드 생성하기[2] Thread3.c Process Thread 실행결과
void *thread_summation(void *arg); int sum=0; int sum1[]={1, 5}; int sum2[]={6, 10}; 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; Process Thread 쓰레드 생성 종료 JOIN RETURN
11
다중 쓰레드 생성하기[3] Thread4.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++; 실행결과
12
임계영역 & 쓰레드의 문제점[1] 컴퓨터가 덧셈하는 원리 int i = 10 int j = 20 j+=i
13
임계영역 & 쓰레드의 문제점[2] 두 개의 쓰레드에 의한 덧셈 원리 int i = 10 i+=10
14
임계영역 & 쓰레드의 문제점[3] 임계영역 쓰레드의 동기화 대표적인 동기화 기법
두개 이상의 쓰레드에 의해서 공유되는 메모리 공간에 접근하는 코드영역 쓰레드의 동기화 공유된 메모리에 둘 이상의 쓰레드가 동시 접근하는 것을 막는 방법 둘 이상의 쓰레드 실행 순서를 컨트롤하는 방법 대표적인 동기화 기법 뮤텍스 세마포어
15
뮤텍스(Mutex)[1] 뮤텍스 뮤텍스의 기본원리 뮤텍스 조작함수
Mutual Exclusion의 줄임말로 쓰레드들의 동시접근을 허용하지 않겠다는 의미 Pthread_mutex_t 타입변수를 가르켜 흔히 뮤텍스라고 함 뮤텍스의 기본원리 임계영역에 들어갈 때 뮤텍스를 잠그고 들어감 임계영역을 빠져 나올 때 뮤텍스를 풀고 나옴 뮤텍스 조작함수 초기화 : pthread_mutex_init (pthread_mutex_t *mutex, const pthread_mutexattr_t *mutexattr) 잠금 : pthread_mutex_lock (pthread_mutex_t *mutex) 잠금 해제 : pthread_mutex_unlock (pthread_mutex_t *mutex) 소멸 : pthread_mutex_destroy (pthread_mutex_t *mutex)
16
뮤텍스(Mutex)[2] 뮤텍스의 동기화 원리 [3] [1] [2] 2.Thread B 진입
pthread_mutex_lock 함수 호출 후 임계영역에 진입 Thread B Thread A 임계영역 Thread B 진입 임계영역 [3] [1] Thread A Pthread_mutux_lock 함수 호출 후 대기상태 1. Pthread_mutex_unlock 함수 호출 후 임계 영역 탈출 Thread B 임계영역 Thread A 진입상태 [2]
17
뮤텍스(Mutex)[3] mutex.c void *thread_increment(void *arg);
char thread1[] = "A Thread"; char thread2[] = "B Thread"; pthread_mutex_t mutx; int number = 0; int main(int argc, char **argv){ pthread_t t1, t2; void *thread_result; int state; state = pthread_mutex_init(&mutx, NULL); if(state){ puts("뮤텍스 초기화 실패"); exit(1); } pthread_create(&t1, NULL, thread_increment, &thread1); pthread_create(&t2, NULL, thread_increment, &thread2); pthread_join(t1, &thread_result); pthread_join(t2, &thread_result); printf("최종 number : %d \n", number); pthread_mutex_destroy(&mutx); return 0; void *thread_increment(void * arg) { int i; for(i=0; i<5; i++){ pthread_mutex_lock (&mutx); sleep(1); number++; printf ("실행 : %s, number : %d \n", (char*)arg, number); pthread_mutex_unlock (&mutx); } 실행결과
18
세마포어(Semaphore)[1] 세마포어 세마포어의 기본원리 세마포어 조작 함수
sem_t 타입의 변수를 가르켜 흔히 세마포어라고 함 세마포어의 기본원리 정수를 가짐 정수 값이 0 이면 실행 불가능 세마포어가 1 이상이면 실행 가능 세마포어는 0 미만은 될수 없고 1 이상은 가능 세마포어 조작 함수 초기화 : sem_init (sem_t *sem, int pshared, unsigned int value) 소멸 : sem_destory (sem_t *sem) 증가 : sem_wait (sem_t *sem) 감소 : sem_post (sem_t *sem)
19
세마포어(Semaphore)[2] 세마포어의 동기화 원리 [1] [2] 1.새로운 데이터를 저장 후 세마포어 하나 증가
2.새로운 데이터를 저장 후 세마포어 하나 증가 Thread A 1. 세마포어가 현재 0이므로 sem_wait 함수 호출 시 대기 상태로 진입 Thread A Data Data Thread B 3. 실행 상태로 돌아와 세마포어를 하나 감소 후 데이터 얻음. 2. 세마포어 값을 하나 감소 시킨 후, 데이터를 가져간다. Thread B [1] [2]
20
세마포어(Semaphore)[3] semaphore.c void *thread_snd(void * arg){ int i;
for(i=0; i<4; i++){ while(number != 0); sleep(1); number++; printf("실행 : %s, number : %d \n", (char*)arg, number); sem_post(&bin_sem); } void *thread_rcv(void * arg){ for(i=0; i<2; i++){ sem_wait(&bin_sem); number--; void *thread_snd(void *arg); void *thread_rcv(void *arg); sem_t bin_sem; int number = 0; char thread1[] = "A Thread"; char thread2[] = "B Thread"; char thread3[] = "C Thread"; int main(int argc, char **argv){ pthread_t t1, t2, t3; void *thread_result; int state; state = sem_init(&bin_sem, 0, 0); //bin_sem은 0으로 설정 if(state != 0){ puts("세마포어 초기화 실패"); exit(1); } pthread_create(&t1, NULL, thread_snd, &thread1); pthread_create(&t2, NULL, thread_rcv, &thread2); pthread_create(&t3, NULL, thread_rcv, &thread3); pthread_join(t1, &thread_result); pthread_join(t2, &thread_result); pthread_join(t3, &thread_result); printf("최종 number : %d \n", number); sem_destroy(&bin_sem); return 0; 실행결과
21
세마포어(Semaphore)[4] semaphore2.c void *thread_snd(void * arg){ int i;
for(i=0; i<4; i++){ number++; printf("실행 : %s, number : %d \n", (char*)arg, number); sem_post(&bin_sem); sem_wait(&bin_sem2); } void *thread_rcv(void * arg){ for(i=0; i<2; i++){ sem_wait(&bin_sem); number--; sem_post(&bin_sem2); void *thread_snd(void *arg); void *thread_rcv(void *arg); sem_t bin_sem bin_sem2; int number = 0; char thread1[] = "A Thread"; char thread2[] = "B Thread"; char thread3[] = "C Thread"; int main(int argc, char **argv){ pthread_t t1, t2, t3; void *thread_result; int state; state = sem_init(&bin_sem, 0, 0); //bin_sem은 0으로 설정 if(state != 0){ puts("세마포어 초기화 실패"); exit(1); } pthread_create(&t1, NULL, thread_snd, &thread1); pthread_create(&t2, NULL, thread_rcv, &thread2); pthread_create(&t3, NULL, thread_rcv, &thread3); pthread_join(t1, &thread_result); pthread_join(t2, &thread_result); pthread_join(t3, &thread_result); printf("최종 number : %d \n", number); sem_destroy(&bin_sem); return 0; 실행결과
22
쓰레드 기반 서버 구현[1] chat_server.c #define BUFSIZE 100
void *clnt_connection(void *arg); void send_message(char *message, int len); void error_handling(char * message); int clnt_number = 0; int clnt_socks[10]; pthread_mutex_t mutx; int main(int argc, char **argv){ int serv_sock; int clnt_sock; struct sockaddr_in serv_addr; struct sockaddr_in clnt_addr; int clnt_addr_size; pthread_t thread; while(1){ clnt_addr_size = sizeof(clnt_addr); clnt_sock = accept(serv_sock, (struct sockaddr*) &clnt_addr, &clnt_addr_size); pthread_mutex_lock(&mutx); clnt_socks[clnt_number++] = clnt_sock; pthread_mutex_unlock(&mutx); pthread_create(&thread, NULL, clnt_connection, (void*)clnt_sock); printf("새로운 연결, 클라이언트 ip : %s \n", inet_ntoa(clnt_addr.sin_addr)); } return 0; void *clnt_connection(void *arg){ int clnt_sock = (int)arg; int str_len = 0; char message[BUFSIZE]; int i; while((str_len = read(clnt_sock, message, sizeof(message))) != 0) send_message(message, str_len); pthread_mutex_lock(&mutx); for(i=0; i<clnt_number; i++){ /*클라이언트 연결 종료 시 */ if(clnt_sock == clnt_socks[i]){ for(; i<clnt_number-1; i++) clnt_socks[i] = clnt_socks[i+1]; break; } clnt_number--; pthread_mutex_unlock(&mutx); close(clnt_sock); return 0; void send_message(char * message, int len){ for(i=0; i<clnt_number; i++) write(clnt_socks[i], message, len);
23
쓰레드 기반 서버 구현[2] chat_client.c #define BUFSIZE 100
#define NAMESIZE 20 void *send_message(void *arg); void *recv_message(void *arg); void error_handling(char * message); char name[NAMESIZE]="[Default]"; char message[BUFSIZE]; int main(int argc, char **argv){ int sock; struct sockaddr_in serv_addr; pthread_t snd_thread, rcv_thread; void *thread_result; sock=socket(PF_INET, SOCK_STREAM, 0); pthread_create(&snd_thread, NULL, send_message, (void*)sock); pthread_create(&rcv_thread, NULL, recv_message, (void*)sock); pthread_join(snd_thread, &thread_result); pthread_join(rcv_thread, &thread_result); close(sock); return 0; } void *send_message(void *arg){ /*메시지 전송 쓰레드 실행 함수*/ int sock = (int)arg; char name_message[NAMESIZE+BUFSIZE]; while(1){ fgets(message, BUFSIZE, stdin); if(!strcmp(message, "q\n")){ /* 'q' 입력 시 종료 */ close(sock); exit(0); } sprintf(name_message, "%s %s", name, message); write(sock, name_message, strlen(name_message)); void *recv_message(void *arg){ int str_len; str_len = read(sock, name_message, NAMESIZE+BUFSIZE-1); if(str_len == -1) return 1; name_message[str_len] = 0; fputs(name_message, stdout);
24
쓰레드 기반 서버 구현[3] chat_server.c & chat_client.c 실행결과 server
Client MR.Lee Client Thomas
25
참고문헌 “TCP/IP 소켓 프로그래밍”, 윤성우 저
“운영체제(Understanding operating Systems)”, 김희철, 박영민, 이금석, 조병호, 최의인 공역
26
Q & A
Similar presentations