Linux 쓰레드 - 기본 - Pthread - 생성과소멸 - 동기화 - 공유변수 - 상호배제 기본? 경량프로세스 (lightweight process: LWP) 일반프로세스는생성시자신만의메모리영역을할당받는다 PCB, code, static, heap, stack 등 : PCB 와스택만별도로할당받고나머지는부모프로세스와공유 생성과전환 (context switch) 시프로세스보다오버헤드가적다. 대부분여러쓰레드가하나의프로세스가되도록운영 OS 에서운영하기나름 새로운프로세스생성시무조건쓰레드생성 exec 등으로변경사항있을때만새메모리할당 프로세스 == 쓰레드그룹 2
기본 Multi-thread 여러개의병행프로세스처럼독립적으로동작 별도스케줄가능 지역변수는별도로사용, 전역변수는공유 자원을공유하므로효율적 하나의프로그램내에서여러개의함수가병행하여실행되는것으로이해 3 기본 사용예 A multithreaded web server 4
기본 쓰레드사용예 Sensor thread Sensor thread GUI thread Sensor thread 5 Pthread POSIX thread IEEE POSIX 1003.1c (1995) 에서표준 thread API 제정 실제구현은하드웨어및 OS 에따라다름 60 개가넘는함수로구성됨 Pthread 사용한프로그래밍 소스내 컴파일옵션 $ gcc pthread [other options] source 6
Pthread 함수분류 쓰레드관리 : pthread_, pthread_attr_ 생성, 분리, 결합 속성관리 상호배제 : pthread_mutex_, pthread_mutexattr_ 쓰레드간동기화, 공유변수관리에사용 Mutex 영역생성, 소멸, lock/unlock Mutex 관련속성의설정또는변경 조건변수 : pthread_cond_, pthread_condattr_ mutex 를공유하는쓰레드간통신에사용 고급동기화구조생성 기타 : pthread_kill, pthread_sigmask, 7 쓰레드관리함수 함수 pthread_create pthread_exit pthread_attr_init pthread_attr_destroy pthread_join pthread_detach pthread_attr_setdetachstate pthread_attr_getdetachstate pthread_self 의미쓰레드생성쓰레드종료쓰레드속성초기화쓰레드속성제거특정쓰레드가종료하여결합할때까지대기쓰레드분리분리상태에대한속성설정분리상태에대한속성질의자신의쓰레드 ID 반환 8
쓰레드생성과소멸 쓰레드생성과소멸 int pthread_create (pthread_t *thread, const pthread_attr_t *attr, void *(*start_routine)(void *), void *arg); void pthread_exit (void *retval); thread 생성이성공할경우생성된쓰레드의 ID attr 속성객체. 기본속성을사용하려면 NULL로설정 start_routine 쓰레드로분기하여실행할함수 arg 쓰레드함수에전달할인자. 사용시필요한타입으로변환반환값호출이성공하면 0, 실패하면 0이아닌에러코드반환 retval 쓰레드종료시반환값의포인터. 9 쓰레드생성과소멸 void *thread (void *data) { int id = *(int *) data; sleep (id); printf( Hello! I m thread #%d\n, id); pthread_exit(null); } int main (void) { pthread_t threads[5]; int rc, t; } for (t = 0; t < 5; t++) { printf( In main: creating thread %d\n, t); rc = pthread_create(&threads[t], NULL, thread, (void *)&t); if (rc) { printf( creation error!\n ); exit(1); } } pthread_exit(null); 10
쓰레드생성과소멸 인자전달 어떤타입이든가능 void * 로만들어전달 인수시점에주의해야한다. void *thread (void *data) { int id; sleep (1); id = *(int *) data; printf( Hello! I m thread #%d\n, id); pthread_exit(null); } 쓰레드함수가인자를전달받기전에 main 이종료하면쓰레드실행에문제가생긴다. 11 쓰레드생성과소멸 속성 (Attributes) default 속성사용 : NULL 지정 별도의 attr 객체사용 attr 객체를생성하고 default 로초기화 pthread_attr_init (pthread_attr_t *attr) attr 객체제거 pthread_attr_destroy (pthread_attr_t *attr) 속성의종류 분리상태 : PTHREAD_CREATE_JOINABLE, PTHREAD_CREATE_DETACHED 스케줄링정책 : PTHREAD_INHERIT_SCHED, PTHREAD_EXPLICIT_SCHED 쓰레드영역 : PTHREAD_SCOPE_SYSTEM, PTHREAD_SCOPE_PROCESS 스택주소 스택크기 그외 12
쓰레드생성과소멸 pthread_exit 쓰레드함수마지막에써준다. cleanup 함수가정의되어있을경우그를실행하고종료 (pthread_cleanup_push 함수사용하여정의 ) 쓰레드종료시에는개방된파일, 동적할당된메모리에대한처리를시스템이자동으로해주지않는다. 프로그래머책임! main 함수 ( 쓰레드를생성한함수 ) 마지막에써준다. main 이종료해도생성한쓰레드가종료하지않도록한다. 13 쓰레드 ID 쓰레드 ID 생성시시스템이부여해주는고유번호 부모쓰레드는 pthread_create 의인자로 ID 를받는다. 생성된쓰레드자신은다음함수를호출 pthread_t pthread_self (void); 반환값호출한쓰레드의 ID를반환 14
쓰레드동기화 쓰레드종료대기 int pthread_join (pthread_t thread, void **thread_return); thread 기다릴쓰레드의 ID thread_return 쓰레드가종료시반환하는값을받아올포인터반환값호출이성공하면 0, 실패하면 0이아닌에러코드반환 15 쓰레드동기화 16
쓰레드동기화 쓰레드분리 int pthread_detach (pthread_t thread); thread 반환값 분리할쓰레드의 ID 호출이성공하면 0, 실패하면 0이아닌에러코드반환 분리된쓰레드는 join 할수없다. 독립적으로수행후종료 pthread_join 또는 pthread_detach 가필요한이유 쓰레드가사용한자원을 < 명시적으로 > OS 에되돌려준다. 기본은 join? 속성이 PTHREAD_CREATE_JOINABLE 로된경우 시스템에따라다를수있다. 17 쓰레드동기화 속성관련예제 18
공유변수 쓰레드의공유변수 각쓰레드는전역변수와 static 변수를공유한다. 19 공유변수 공유변수사용시의문제점 20
공유변수 왜정확한값이나오지않을까? C 프로그램상에서는문제가없다. CPU 가일하는수준으로내려가면 하나의 C 문장이여러단계의기계어로나누어진다. CPU 는한번에하나의쓰레드만실행 일정시간수행후교체 명령실행의중간단계에실행쓰레드가교체되면값이보존되지않을수도있다! race condition 공유변수에대한보호막필요! Mutual Exclusion ( 상호배제 ) 21 상호배제 상호배제관련함수 함수 의미 pthread_mutex_init mutex 객체초기화 pthread_mutex_destroy mutex 객체제거 pthread_mutexattr_init mutex 속성객체초기화 pthread_mutexattr_destroy mutex 속성객체제거 mutex 영역에들어가기위한 lock 요청 (block 상 pthread_mutex_lock 태에서대기 ) mutex 영역에들어가기위한 lock 요청 ( 대기하지 pthread_mutex_trylock 않음 ) pthread_mutex_unlock mutex 영역에서빠져나올때 lock 돌려주기 22
상호배제 mutex 객체초기화 mutex 를이용해임계영역 (critical region) 을구현하려면먼저 mutex 객체를선언하고초기화해야한다. int pthread_mutex_init (pthread_mutex_t *mutex, const pthread_mutexattr_t *attr); mutex mutex 객체 attr 반환값 mutex 속성객체. default로설정하려면 NULL 호출이성공하면 0, 실패하면 0이아닌에러코드반환 pthread_mutex_t mutex = PTHREAD_MUTEX_INITIALIZER; == pthread_mutex_t mutex; pthread_mutex_init (&mutex, NULL); 23 상호배제 mutex 객체삭제 int pthread_mutex_destroy (pthread_mutex_t *mutex); mutex mutex 객체 반환값 호출이성공하면 0, 실패하면 0 이아닌에러코드반환 lock 상태의 mutex 객체는삭제해서는안된다. 24
상호배제 임계영역출입 int pthread_mutex_lock (pthread_mutex_t *mutex); int pthread_mutex_trylock (pthread_mutex_t *mutex); int pthread_mutex_unlock (pthread_mutex_t *mutex); mutex mutex 객체 반환값 호출이성공하면 0, 실패하면 0 이아닌에러코드반환 lock: 임계영역에들어갈권리 (lock) 를요청한다. 누군가 lock 해놓은상태에서는수행을중단하고기다린다. unlock: 임계영역에서작업을끝내고 lock 을해제한다. 대기중인다른쓰레드가 lock 을얻어수행할수있다. trylock: lock 을요청한다. lock 을획득할수없으면대기하지않고돌아온다. 25 mutex 예제 정확한값출력 시간이더걸린다. pthread_mutex_t mutex; 상호배제 int main (void) { pthread_mutex_init (&mutex, NULL); pthread_mutex_destroy (&mutex); } void *count (void *data) { for ( i=0; i<niters; i++) { pthread_mutex_lock(&mutex); cnt++; pthread_mutex_unlock(&mutex); } } 26
! 효율적인프로그램을작성할수있다! 서버나 GUI 에서일상적으로사용된다. 주의사항 쓰레드종료시자동청소가어렵다 부모가책임지도록프로그램해야한다. 공유변수에동시에변경을가할경우오류가생기지않도록상호배제를구현해야한다. 27