데이터베이스 실험실 석사 2학기 김기훈 Khkim@dblab.hannam.ac.kr TCP/IP Socket Programming… 제 17장 멀티쓰레드 기반의 서버구현 데이터베이스 실험실 석사 2학기 김기훈 Khkim@dblab.hannam.ac.kr.

Slides:



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

TCP 서버/클라이언트 동작 원리 - (1) TCP 서버/클라이언트 예 웹 서버 웹 클라이언트 웹 클라이언트
Linux/UNIX Programming APUE (The Environment of a UNIX Process)
2016 ITA 1월 강의 C Programming -4일차- 포인터배열 및 이중포인터 정대진 ( )
6장. 멀티스레드 멀티스레드 프로그래밍의 필요성을 이해하고 기본 개념을 익힌다.
13장 소켓.
C 프로그래밍 소개 숙명여대 창병모 2011 가을.
Network Lab. Young-Chul Hwang
제 8 장  파서 생성기 YACC 사용하기.
Department of Computer Engineering
인공지능실험실 석사 2학기 김승겸 TCP/IP Socket Programming… 제 10장 멀티태스킹 기반의 서버구현 인공지능실험실 석사 2학기 김승겸
Signal & Inter-Process Communication
Department of Computer Engineering
쉽게 풀어쓴 C언어 Express 제17장 동적 메모리와 연결 리스트 C Express.
Multi-thread Programming
C언어: 배열 (Arrays).
TCP Client/Server Program
Network Lab. Seoung Hyeon, Lee
얇지만 얇지 않은 TCP/IP 소켓 프로그래밍 C 2판
6 프로세스 생성과 실행.
버퍼 오버플로우에 대한 대책과 발전된 공격 안전한 함수 사용 버퍼 오버플로우에 취약한 함수 사용하지 않기
Linux System Programming
6장 비연결형 지향 프로토콜 Database Lab 강 우 석.
인터넷 주소 변환 School of Electronics and Information. Kyung Hee University.
14장 소켓.
제 12장 I/O멀티플렉싱(Multiplexing)
10장 메모리 관리.
쉽게 풀어쓴 C언어 Express 제17장 동적 메모리와 연결 리스트 C Express.
쉽게 풀어쓴 C언어 Express 제17장 동적메모리와 연결리스트 C Express.
Department of Computer Engineering
동적메모리와 연결리스트 컴퓨터시뮬레이션학과 2016년 봄학기 담당교수 : 이형원 E304호,
3장. 포인터, 배열, 구조체 포인터, 배열, 구조체 학습목표 기본적 데이터 타입
Department of Computer Engineering
Multi-thread Programming
멀티쓰레드 기반의 서버구현 School of Electronics and Information.
임베디드 실습 #1 기초 실습 Hanbat National University Prof. Lee Jaeheung.
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 컴파일.
Department of Computer Engineering
제 3 장 상수와 변수
10장 C 표준 파일 입출력 子曰 學而時習(실습?)之 不亦悅乎.
텀 프로젝트 보고서 - 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학기 조정희
Department of Computer Engineering
Operating System Multiple Access Chatting Program using Multithread
6장 반복제어문 for 문 while 문 do while 문 기타 제어문.
C89(C++03) 프로그래밍 (Part 2) 7 배열 8 변수 범위 9 포인터 10 유도 자료형.
Department of Computer Engineering
제 16장 입력과 출력 스트림의 완벽 분리 TCP/IP Socket Programming… 데이터베이스 실험실
Multi-thread Programming
컴퓨터 프로그래밍 기초 - 11th : 파일 입출력 및 구조체 -
실습과제 1번 생성된 파일 basic.txt를 프로젝트 폴더에서 메모장으로 열고 내용을 확인
어서와 C언어는 처음이지 제16장.
Windows System Programming
argc, argv 의 사용방법 #include <stdio.h>
Signal & Inter-Process Communication
C 13장. 입출력 라이브러리 #include <stdio.h> int main(void) { int num;
C.
printf("Global Korea\n");
Presentation transcript:

데이터베이스 실험실 석사 2학기 김기훈 Khkim@dblab.hannam.ac.kr TCP/IP Socket Programming… 제 17장 멀티쓰레드 기반의 서버구현 데이터베이스 실험실 석사 2학기 김기훈 Khkim@dblab.hannam.ac.kr

목차 쓰레드란 무엇인가 쓰레드 생성하기 다중 쓰레드 생성하기 임계영역 & 쓰레드의 문제점 뮤텍스(mutex) 세마포어(Semaphore) 쓰레드 기반 서버 구현

쓰레드란 무엇인가[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

쓰레드란 무엇인가[2] 프로세스와 쓰레드

쓰레드 생성하기[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, 실패 시 이외의 값 리턴

쓰레드 생성하기[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 쓰레드 생성 종료

쓰레드 생성하기[3] pthread_join 함수 th : th에 인자로 들어오는 ID의 쓰레드가 종료할 때까지 실행 지연 thread_return : 쓰레드가 종료 시 반환하는 값에 접근할 수 있는 2차원포인터 #include <pthread.h> int pthread_join(pthead_t * th, void **thread_return); ); 성공 시 0, 실패 시 이외의 값 리턴

쓰레드 생성하기[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 대기상태

다중 쓰레드 생성하기[1] 임계영역(Critical Section)과 쓰레드에 안전한 함수의 호출 임계영역 두개 이상의 쓰레드에 의해서 동시에 실행되면 안 되는 영역 쓰레드 관점에서 볼 때 함수의 종류 쓰레드 불안전한 함수(Thread-unsafe Function) 단일 쓰레드 모델에서는 사용 가능함 함수이지만 다중 쓰레드 모델에서는 사용할 수 없는 함수(gethostbyname) 쓰레드 안전한 함수(Thread-safe Function) 다중 쓰레드 모델에서 사용 가능한 함수(gethostbyname_r) 불안전한 함수를 안전한 함수로 변경 컴파일시 –D_REENTRANT를 옵션으로 넣어 주는 방식으로 매크로를 선언

다중 쓰레드 생성하기[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

다중 쓰레드 생성하기[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++; 실행결과

임계영역 & 쓰레드의 문제점[1] 컴퓨터가 덧셈하는 원리 int i = 10 int j = 20 j+=i

임계영역 & 쓰레드의 문제점[2] 두 개의 쓰레드에 의한 덧셈 원리 int i = 10 . . . . . i+=10

임계영역 & 쓰레드의 문제점[3] 임계영역 쓰레드의 동기화 대표적인 동기화 기법 두개 이상의 쓰레드에 의해서 공유되는 메모리 공간에 접근하는 코드영역 쓰레드의 동기화 공유된 메모리에 둘 이상의 쓰레드가 동시 접근하는 것을 막는 방법 둘 이상의 쓰레드 실행 순서를 컨트롤하는 방법 대표적인 동기화 기법 뮤텍스 세마포어

뮤텍스(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)

뮤텍스(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]

뮤텍스(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); } 실행결과

세마포어(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)

세마포어(Semaphore)[2] 세마포어의 동기화 원리 [1] [2] 1.새로운 데이터를 저장 후 세마포어 하나 증가 2.새로운 데이터를 저장 후 세마포어 하나 증가 Thread A 1. 세마포어가 현재 0이므로 sem_wait 함수 호출 시 대기 상태로 진입 Thread A Data Data Thread B 3. 실행 상태로 돌아와 세마포어를 하나 감소 후 데이터 얻음. 2. 세마포어 값을 하나 감소 시킨 후, 데이터를 가져간다. Thread B [1] [2]

세마포어(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; 실행결과

세마포어(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; 실행결과

쓰레드 기반 서버 구현[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);

쓰레드 기반 서버 구현[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);

쓰레드 기반 서버 구현[3] chat_server.c & chat_client.c 실행결과 server Client MR.Lee Client Thomas

참고문헌 “TCP/IP 소켓 프로그래밍”, 윤성우 저 “운영체제(Understanding operating Systems)”, 김희철, 박영민, 이금석, 조병호, 최의인 공역

Q & A