[제11장] POSIX 스레드

디지털라이프 | 2007/06/25 19:06

=================================================================
  * 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_

Trackback Address :: http://badnom.com/trackback/293
Name
Password
Homepage
Secret
< PREV |  1  |  ...  744  |  745  |  746  |  747  |  748  |  749  |  750  |  751  |  752  |  ...  988  |  NEXT >