[제11장] POSIX 스레드
=================================================================
* Subject : [제11장] POSIX 스레드
* Writer: w0rm9 (research.hackerschool.org)
* Date: 2004/02/11
=================================================================
/* 멋진 몽이님 강의를 중심으로 정리했습니다.
* 사용한 소스도 물론 몽이님이 강의때 사용한 소스입니다.
*/
0x01. 스레드
스레드 - 한 프로그램의 전체 실행 흐름
[w0rm9@work THREAD]$ cat test.c
void func(void)
{
printf("why call me?\n");
}
int main()
{
printf("start!\n");
func();
printf("end!!\n");
}
실행된 후의 흐름 : 시작 -> start! 출력 -> func 호출 -> why call me 출력 -> end!! 출력 -> 종료
이것을 바로 스레드. 즉, 프로그램의 실행 흐름
fork와 비교했을 때 멀티 스레드의 장점
1. 메모리 낭비나 시스템 부하가 fork()보다 훨 적다
2. 프로그램 내의 전역 변수나 디스크립터 등을 공유할 수 있다
■ 첫번째 스레드 프로그램
사용법)
#include <pthread.h>
int pthread_create(pthread_t *thread, pthread_attr_t *attr, void *(*start_routine)(void *), void *arg);
=> pthread_create()의 첫번째 인수는 pthread_t에 대한 포인터, 스레드가 생성될 때 식별자는 이 포인터가 가리키는 변수에 저장된다.
다음 인수에는 스레드의 속성, 세번째 인수는 스레드에게 실행을 시작하는 함수, 네번째 인수는 그 함수로 전달되는 인수이다.
테스트)
[w0rm9@work THREAD]$ cat pthread1.c
#include <stdio.h>
#include <pthread.h>
void *now_time(void *arg){ // 스레드2 : 현재 시간을 1초 간격으로 화면에 출력
while(1){
system("/bin/date");
sleep(1);
}
}
int main()
{
char buffer[1024];
pthread_t a_thread;
pthread_create(&a_thread, 0, now_time, 0); // 스레드 생성
while(1){
fgets(buffer, 1024, stdin); // 스레드1 : 사용자의 입력을 기다리고 그 내용을 화면에 출력
printf("you typed : %s\n", buffer);
}
}
[w0rm9@work THREAD]$ gcc -o pthread1 pthread1.c -lpthread
[w0rm9@work THREAD]$ ./pthread1
2004. 02. 12. (목) 21:20:24 KST
2004. 02. 12. (목) 21:20:25 KST
사랑2004. 02. 12. (목) 21:20:26 KST
해
you typed : 사랑해
2004. 02. 12. (목) 21:20:27 KST
히?004. 02. 12. (목) 21:20:28 KST
you typed : 히히
2004. 02. 12. (목) 21:20:29 KST
2004. 02. 12. (목) 21:20:30 KST
■ pthread_exit, pthread_join
사용법)
#include <pthread.h>
int pthread_exit(void *retval);
int pthread_join(pthread_t th, void **thread_return);
=> pthread_exit()는 스레드가 끝날 때 호출
pthread_join()은 프로세스가 자식 프로세스를 기다리기 위해 사용하는 wait의 스레드 버전
첫번째 인자는 스레드 식별자, 두번째 인자는 스레드로부터 반환값에 대한 포인터의 포인터
테스트)
[w0rm9@work THREAD]$ cat pthread2.c
#include <stdio.h>
#include <pthread.h>
void *now_time(void *arg)
{
printf("the arg : %s\n", arg); // 3. 넘져준 인자값이 출력됨
pthread_exit("oh my god~!!!!!!!");
}
int main()
{
char buffer[1024];
pthread_t a_thread;
void *result;
pthread_create(&a_thread, 0, now_time, "I am your father"); // 1. now_time 스레드에 "I am your father"이라는 인자값을 넘겨줌.
pthread_join(a_thread, &result); // 2. 스레드2가 종료하길 기다림
printf("return value : %s\n", result);
}
[w0rm9@work THREAD]$ gcc -o pthread2 pthread2.c -lpthread
[w0rm9@work THREAD]$ ./pthread2
the arg : I am your father
return value : oh my god~!!!!!!! // 스레드2의 반환값
0x02. 동기화
동기화 - 두 개 이상의 함수 혹은 프로그램이 서로의 흐름을 알맞게 조율하는 것
스레드1 : 사용자의 입력을 받기만함
스레드2 : 사용자의 입력을 출력하기만함
#include <stdio.h>
#include <pthread.h>
char buffer[1024];
void *thread_func(void *arg)
{
while(1){
printf("you typed : %s\n", buffer);
}
}
int main(){
pthread_t a_thread;
pthread_create(&a_thread, 0, thread_func, 0);
while(1){
fgets(buffer, 1024, stdin);
}
}
스레드2의 출력 루틴이 스레드1의 입력 루틴을 "기다려줘야"할 필요성이 생김
즉, 입력이 완료 되면 -> 출력이 되도록
■ 세마포어를 이용한 동기화
사용법)
#include <semaphore.h>
int sem_init(sem_t *sem, int pshared, unsigend int value);
int sem_wait(sem_t *sem);
int sem_post(sem_t *sem);
int sem_destroy(sem_t *sem);
=> sem_init()는 세마포어 오브젝트를 초기화
sem_wait()는 세마포어 값이 1보다 커질 때까지 기다림
sem_post()는 세마포어 값을 1증가
sem_destroy()는 세마포어 사용 후 리소스 정리
테스트)
[w0rm9@work THREAD]$ cat sem.c
#include <stdio.h>
#include <pthread.h>
#include <semaphore.h>
char buffer[1024];
sem_t bin_sem;
void *thread_func(void *arg) // 스레드2
{
while(1){
sem_wait(&bin_sem); // 3. 초기화에서 0 이기 때문에 1보다 커질 때까지 기다림
printf("you typed : %s\n", buffer); // 5. 스레드1에서 세마포어값이 1이 되면 블락상태를 해제, 동시에 세마포어값을 -1 감소
}
}
int main()
{
pthread_t a_thread;
sem_init(&bin_sem, 0, 0); // 1. 초기화
pthread_create(&a_thread, 0, thread_func, 0); // 2. 스레드 생성
while(1){ // 스레드1
fgets(buffer, 1024, stdin);
sem_post(&bin_sem); // 4. 스레드1에서 입력이 완료되면 세마포어 값이 1증가
}
}
[w0rm9@work THREAD]$ gcc -o sem sem.c -lpthread
[w0rm9@work THREAD]$ ./sem
안녕
you typed : 안녕
된다.
you typed : 된다.
■ 뮤텍스를 이용한 동기화
사용법)
#include <pthread.h>
int pthread_mutex_init(pthread_mutex_t *mutex, const pthread_mutexattr_t *mutexattr);
int pthread_mutex_lock(pthread_mutex_t *mutex);
int pthread_mutex_unlock(pthread_mutex_t *mutex);
int pthread_mutex_destroy(pthread_mutex_t *mutex);
=> init() 초기화, lock() 락, unlock() 락해제, destroy() 리소스 정리
테스트)
[w0rm9@work THREAD]$ cat mutex.c
#include <stdio.h>
#include <pthread.h>
#include <semaphore.h>
char buffer[1024];
pthread_mutex_t mutex;
void *function(void *arg) // 스레드2
{
while(1){
pthread_mutex_lock(&mutex); // 4. LOCK 되어진 상태일 경우에 스레드의 실행을 멈춘다. 누군가 UNLOCK을 호출하면, 흐름을 재개하고,
printf("you typed : %s\n", buffer); // 동시에 UNLOCK된 것을 다시 LOCK 모드로 바꾼다.
}
}
int main()
{
pthread_t a_thread;
pthread_mutex_init(&mutex, 0); // 1. 뮤텍스가 초기화 됨.(UNLOCK 상태, 즉, 수도꼭지 열린 상태)
pthread_mutex_lock(&mutex); // 2. 뮤텍스의 모드를 LOCK으로 변경
pthread_create(&a_thread, 0, function, 0); // 3. 스레스 생성
while(1){ // 스레드1
fgets(buffer, 1024, stdin);
pthread_mutex_unlock(&mutex); // 5. 뮤텍스의 모드를 UNLOCK으로 변경
}
}
[w0rm9@work THREAD]$ gcc -o mutex mutex.c -lpthread
[w0rm9@work THREAD]$ ./mutex
사랑해~
you typed : 사랑해~
진짜루~~
you typed : 진짜루~~
■ 스레드 종료
1. 스레드 자신이 자신을 종료 -> pthread_exit()
2. 다른 스레드가 종료시켜줌 -> pthread_cancel(pthread_t thread)
/* 나머지는 생략~~ */
_eof_
