Multi-thread Programming Department of Computer Engineering Kyung Hee University. Choong Seon Hong
Thread의 개요 Thread란 Process와의 차이점 한 프로그램에서 여러 실행 흐름 스택을 제외한 나머지 메모리 영역을 공유 전역변수, 파일 디스크립터, 시그널 핸들러 그리고 현재 디렉토리 상태를 thread 생성자인 process와 공유 일부 메모리를 공유하므로 thread간 통신이 편리 보다 간단한 컨텍스트 스위칭 (context switching)
fork 함수 호출을 통한 process의 생성 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 원본 process
Process and Thread 실행 흐름 실행되고 있는 일의 단위 Thread_1 Thread_2 Process_1 Operating System Thread_3 Thread_1 Thread_2 Process_2 Thread_3
Thread 생성 1 #include <pthread.h> int pthread_create (pthread_t * thread, pthread_attr_t * attr, void*(*start_routine)(void*), void * arg ); thread : 생성된 thread의 ID를 저장할 변수의 포인터를 인자로 전달 attr : 생성하고자 하는 thread의 특성을 설정할 때 사용(일반적으로 NULL 전달) start_routine : thread 생성 후 실행해야 하는 함수를 가리키는 포인터 arg : thread에 의해 호출되는 함수에 전달하고자 하는 인자 값
Thread 생성 예제 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("thread 생성 오류"); exit(1); } printf("생성된 thread의 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 실행중");
Thread compile -lpthread -D_REENTRANT pthread 라이브러리(libpthread.so)를 링크하겠다는 의미 -D_REENTRANT 프로그램 내에서 “#define _REENTRANT” 선언과 같은 효과 -D_REENTRAN 옵션을 컴파일 시에 주면 _REENTRANT가 설정되어 thread들은 각각 고유한 errono를 갖게 됨 따라서 일반 함수 호출 시에 error 변수나 perror() 함수를 그대로 사용할 수 있음
Thread 생성 2 pthread_join 함수 인자로 전달되는 ID에 해당하는 thread가 종료될 때까지 대기 상태로 들어가기 위해서 호출하는 함수 th : th에 인자로 들어오는 ID thread가 종료할 때까지 실행을 지연 thread_return : thread가 종료시 반환하는 값에 접근할 수 있는 2차원 포인터 #include <pthread.h> int pthread_join(pthread_t th, void **thread_return);
Thread 생성 예제 2 프로그램 예제(thread2.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); /* thread 생성 */ if(state != 0){ puts("thread 생성 오류"); exit(1); } printf("생성된 thread의 ID : %d \n", t_id); /* thread 종료 시까지 main함수의 실행을 지연 */ state = pthread_join(t_id, &t_return); /* 리턴 값 저장 */ puts("thread Join 오류"); printf("main함수 종료, thread 리턴 %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, "thread 종료 됨!\n"); for(i=0; i<3; i++){ sleep(2); puts("thread 실행중"); } return p;
Thread 생성 예제 분석 Process Process 생성 thread thread 생성 join 대기상태 리턴 종료 종료 thread1.c thread2.c
Thread 관련 함수 Thread ID 얻기 Thread 종료 #include <pthread.h> pthread_t pthread_self(void); #include <pthread.h> void pthread_exit(void *retval)
Multi-thread 생성 모델 d Process Thread Thread 쓰레드 생성 쓰레드 생성 JOIN 리턴 종료
Multi-thread 예제 프로그램 예제(thread3.c, thread4.c) [ 그림 17-7 ]
Thread의 동기화 문제 한 thread가 공유 데이터를 액세스하는 도중 다른 thread가 이 공유 데이터를 액세스하게 되면 그 데이터의 값을 정확히 예측 할 수 없음 동기화 문제 임계영역 (critical section) 두 개 이상의 thread에 의해서 동시에 실행되면 안 되는 영역
컴퓨터가 덧셈을 하는 기본 원리 Int i = 10; int j = 20; j += i; … … …… …… i = 10 2.덧셈연산 임시 메모리 임시 메모리 메인 메모리 메인 메모리 … … 20 10+20 i = 10 i = 10 j = 20 j = 30 1.임시저장 3.연산 결과 대입 …… ……
두 개의 Thread에 의한 덧셈 연산 int i = 10; 전역변수 ………… i += 10 ; //Thread에 의해 두 번 실행 A Thread 실행 [1단계] A Thread 실행 2.연산결과저장 20 2.덧셈연산 1.임시저장 10 + 10 i = 20 20 .. …. 1.임시저장 i = 10 [3단계] ….. B Thread 실행 3.덧셈 연산 4.연산 결과 저장 10 + 10 2.임시저장 1.임시저장 i = 20 20 …. [2단계]
동기화(Synchronization) 임계영역 둘 이상의 thread에 의해서 공유되는 메모리 공간에 접근하는 코드영역. 동기화 첫째 : 공유된 메모리에 둘 이상의 thread가 동시 접근하는 것을 막는 행위 둘째 : 둘 이상의 thread 실행순서를 컨트롤(control)하는 행위 대표적인 동기화 기법 Mutex, Semaphore
뮤텍스 (Mutex) 뮤텍스 (Mutex Mutual Exclusion) 기본 원리 뮤텍스를 조작하는 함수들 pthread_mutex_t 타입의 데이터 변수를 가리켜 뮤텍스라고 표현한다. 일종의 문고리에 해당한다. 기본 원리 임계영역에 들어 갈 때 뮤텍스(문고리)를 잠그고 들어간다. 임계영역에서 빠져 나올 때 뮤텍스를 풀고 나간다. 뮤텍스를 조작하는 함수들 뮤텍스 초기화 함수 : int pthread_mutex_init(pthread_mutex_t *mutex, const pthread_mutexattr_t *mutexattr); 뮤텍스 소멸 함수 : int pthread_mutex_destroy(pthread_mutex_t *mutex); 뮤텍스 잠그는 함수 : pthread_mutex_lock(pthread_mutex_t *mutex); 뮤텍스 풀어주는 함수 : pthread_mutex_unlock(pthread_mutex_t *mutex);
뮤텍스의 동기화 원리 Critical Section 2. Thread B 진입 pthread_mutex_lock 함수 호출 후 임계영역에 진입 Thread B Thread A Critical Section Thread B 진입 Critical Section Thread A 1.pthread_mutex_unlock 함수 호출 후 임계 영역 탈출 pthread_mutex_lock 함수 호출 후 대기 상태 Thread B Critical Section Thread A 진입 상태
프로그램 예제 프로그램 예제 mutex.c 실행결과.
세마포어 (Semaphore) 세마포어 기본 원리 세마포어를 조작하는 함수들 sem_t 타입의 변수를 가리켜 흔히 세마포어라 표현한다. 기본 원리 세마포어는 정수를 지닌다. 정수의 값이 0이면 실행 불가를 의미한다. 세마포어가 1이상이 되면 실행 가능을 의미한다. 세마포어는 0미만이 될 수 없지만 1이상은 될 수 있다 0과 1의 상태만을 지니는 세마포어를 가리켜 바이너리 세마포어라 한다. 세마포어를 조작하는 함수들 세마포어 초기화 함수 : sem_init 세마포어 소멸 함수 : sem_destroy 세마포어 감소 함수 : sem_wait 세마포어 증가 함수 : sem_post
세마포어 조작 함수 #include<semaphore.h> sem_init : 세마포어를 초기화하는 함수. sem : 초기화하고자 하는 세마포어 변수의 포인터 pshared : 0-> 하나의 process 내에서만 사용, ‘0’이외의 값은 여러 개의 process가 공유할 수 있는 세마포어 생성 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);
세마포어 동기화 원리 Data Data 즉, B thread가 먼저 데이터 영역에 접근하는 일은 발생하지 않음 Thread A 2.새로운 데이터를 저장 한 후 세마포어 하나 증가 1. 새로운 데이터를 저장 후 세마포어 하나 증가 Thread A Thread A 세마포어가 현재 0 이므로 sem_wait 함수 호출 시 대기 상태로 진입 Data Data 2. 세마포어 값을 하나 감소 시킨 후, 데이터를 가져간다 3.실행 상태로 돌아와 세마포어를 하나 감소 후 데이터 얻음 Thread B Thread B 즉, B thread가 먼저 데이터 영역에 접근하는 일은 발생하지 않음
프로그램 예제 프로그램 예제 총 3개의 thread가 생성 실행결과. semaphore.c 그 중 하나는 number 변수를 1로 만들고, 나머지 두 thread는 number 변수의 값이 1인 경우에만 0을 만든다. number의 의미 새로운 데이터의 유무를 나타내는 변수 실행결과.
프로그램 예제 dd 프로그램 예제 semaphore2.c Thread A number = 0 bit_sem = 0 B-2. number=0 Thread A number = 0 A-2. bit_sem=1 B-1. bit_sem=0 bit_sem = 0 Thread B A-3. bit_sem2=0 B-3. bit_sem2=1 bit_sem2 = 0 semaphore2.c의 동기화 과정
프로그램 예제 dd a case - semaphore2.c Thread A number = 1 number = 0 B-2. number=0 Thread A number = 1 number = 0 number = 0 A-2. bit_sem=1 B-1. bit_sem=0 bit_sem = 0 bit_sem = 1 Thread B A-3. bit_sem2=0 B-3. bit_sem2=1 bit_sem2 = 1 bit_sem2 = 0 semaphore2.c의 동기화 과정
프로그램 예제 Thread 기반 채팅 서버 & 클라이언트 chat_server.c chat_client.c