시스템 프로그래밍(6)

조권휘·2022년 8월 22일
0

시스템 프로그래밍

목록 보기
6/14

Thread Background

  • Concurrent processing은 process가 너무 무겁다.
  • process에는 address space(code), OS resource(open file)..., contest(실행 상태 정보, reg).. 등이 존재한다.
  • 즉, fork()를 한다면 시간과 memory가 매우 costly하다.
  • 이러한 단점들이 존재했기 때문에 공유할 수 있는 것은 공유하고 실행 할 때 다른 것만 분리를 하는 것이 필요해졌다.

Thread

  • process 내부에서 독립적인 제어 흐름을 가지는 단위
  • 1개의 process는 1개의 thread를 가진다.
  • multi thread process는 1개의 process 내에 여러개의 thread를 가진다. → multi thread는 process를 공유한다.
  • thread는 CPU의 scheduling 단위이다.
  • thread 구성 : thread ID, program counter, register를 부여 / stack은 별도로 지원한다.

  • 대부분 현대 OS는 multi thread를 지원한다.
  • multi thread 사용 예시 : web browser / word processor / ...
  • 대부분 OS는 MT-safe lib func을 지원한다.
  • Multi Thread - safe library function : multi thread를 목적으로 생각한 function들을 모아둔 library
  • ex) POSIX pthread standard API : OS 개발자가 implement한다.

pthreads

  • <pthread.h> 헤더파일의 pthread library
  • libpthread.a library를 link해야한다.
  • compile option : -lpthread
$ gcc test.c -lpthread

pthread_create

#include <pthread.h>

int pthread_create(pthread_t *thread, 
		pthread_attr_t* attr,
		void *(*start_routine)(void *), 
        void *arg);
  • thread를 생성하는 API
  • *thread : thread id
  • *attr : 환경 설정(default : NULL)
  • *start_routine : 실행 작업(=function)
  • *arg : start_routine에 사용되는 인자
  • return : 성공 시 0 / 실패 시 error number

  • 모든 thread는 생성되면 독립적으로 동작한다.
  • 기본적으로 process는 main thread를 가진다.
  • 1개의 process 내에 thread의 생성에는 maximum이 정해져 있다. (default : 388547)

Terminating pthread

  • pthread가 종료되는 여러가지 방법이 존재한다.
    1) 전달 함수가 종료되면 thread가 종료
    2) pthread exit을 불러서 thread 종료
    3) pthread_id를 이용해서 pthread_cancel을 호출하여 종료
    4) process 자체가 종료되면 관련 thread들이 전부 종료
void pthread_exit(void *retval)
  • 특정 thread에서 자신 thread를 종료한다.
  • void type은 모든 자료형을 포괄하기 위해 사용된다.
  • pthread_exit을 할 때 open file을 닫지 않고, process가 종료될 때 닫는다.

if main()함수가
1) pthread_exit() : 다른 thread는 실행하고 main만 종료됨
2) exit() : 다른 모든 thread가 종료(process가 종료)


Thread Attribute

  • thread가 생성될 때, thread의 속성은 joinable / detached로 정의된다.

1. joinable thread

  • thread가 종료되면 기존 thread와 합쳐진다 → resource 회수
  • 생성 시 default thread attribute이다.

2. detached thread

int pthread_detach(pthread_tid);
  • 독립적으로 관리되며 thread 종료 시 즉시 resource를 반환한다.
  • pthread_detach 함수로 분리해야 한다.
  • 한번 type을 detached로 바꾸면 다시 joinable로 돌아가지 못한다.

pthread_join

int pthread_join(pthread_t tid, void **retval);
  • id의 thread가 종료될 때 까지 기다리는 함수
  • arg를 넘겨줄 때까지 block된다.
  • 만약 취소가 된다면 PTHREAD_CANCELED가 retval에 저장된다.

**retval에서 **인 이유?

  • exit에서 보내는 type = *retval 이 주소 or integer일 지 모르기 때문에, 그 값을 담을 수 있는 pointer 변수이다.

Getting Thread ID

pthread_self

int pthread_self(void);
  • return : 호출 된 thread의 id

pthread_equal

int pthread_equal(pthread_t t1, pthread_t t2);
  • return : 두 thread의 id가 동일하면 nonzero / 다르면 0

Thread를 비교할 때 " == " 사용하지 말기

  • t1, t2는 id가 아닌 key고, key의 struct 내부에 있는 id를 가져와서 비교하는 것이기 때문

Thread Cancellation

pthread_cancel(pthread_t tid)
  • thread가 완료되기 전에 종료하고싶을 때 사용

Cancellation type

asynchronous calnel

  • 호출 시 즉시 thread를 종료
  • 만약 thread가 현재 cancel 요청이 왔을 때 resource는 바로 반환한다.
  • 중요한 작업 / 계산 중 / 공유 중일 때는 불시에 out될 수 있는 문제가 있다.

deferred cancel

  • 지정 지점(cancellation point)까지 다 수행하고 cancel
  • pthread_testcancel() 이 호출지점 → 이 후 cleanup
int pthread_setcancelstate(int state, int *oldstate);
int pthread_setcanceltype(int type, int *oldtype);

  • state(mode) 내부 인자 → PTHREAD_CANCEL_?? 형식으로 입력

Implicit sharing

  • 암묵적 공유 → user가 모르게 data가 공유되어 사용되는 상황
  • 주소 값을 create할 때 사용하는 일에 발생한다.
  • 현재 thread와 new thread 사이의 i 값을 공유

Mutex

Thread Synchronization

  • 공통된 자원에 thread가 함께 접근했을 때 발생되는 문제
  • race condition과 유사한 상황

Mutex

  • 여러 thread 사이의 shared data를 보호하기 위해 lock을 하며 사용한다.
  • 한 순간에 1개의 thread를 lock(acquire) 한다.
  • 만일 여러 thread가 lock을 시도할 경우 OS가 1개의 thread만 lock 시킨다.
  • 이 외의 thread들은 unlock이 될 때까지 대기한다.

Critical section

  • shared data를 다루는 code 영역
  • 오직 한 순간에 1개의 thread만 접근(작업)하도록 해야한다.
  • mutually exclusive(상호 배제)를 해야한다.

pthread mutex creation

/* mutex object creation & destruction */
int pthread_mutex_init(*mutex, *attr);

int pthread_mutex_destroy(*mutex);

/* mutex attribute creation & destruction */
int pthread_mutexattr_init(*attr);

int pthread_mutexattr_destroy(*attr);

pthread_mutex_t *mutex
pthread_mutexattr_t *attr
  • Mutex는 초기에 unlocked 상태이다.
  • Mutex 변수는 선언 이후 초기화를 해줘야한다.
  • Mutex 변수 초기화 방법
    1) statically : pthread_mutex_t mymutex = THREAD_MUTEX_INITIALIZER
    2) dynamic : pthread_mutex_init(attr)

pthread_mutexattr의 정의

  • protocol : priority inversion을 막는 것
  • prioceiling : priority ceiling(최고값) 설정
  • process-shared : process 사이 mutex
    → 일반적으로는 그냥 default(NULL) 사용

Mutex Lock/Unlock

int pthread_mutex_lock(*mutex);

int pthread_mutexattr_unlock(*mutex);

pthread_mutex_t *mutex
pthread_mutexattr_t *attr
  • return : 성공 시 0 / 실패 시 error number
  • lock() : thread가 lock 상태라면 다른 thread는 block되어서 대기한다.
  • unlock() : block 상태를 해제한다.
  • unlock이 error나는 경우는 이미 unlock인 경우이거나 또 다른 thread가 mutex를 잡고 있는 경우이다.
int pthread_mutex_trylock(*mutex);
  • non-blocking lock으로 lock이 가능한 상태가 아니면 바로 block을 한다.

Advisory locking

  • programmer가 직접 lock을 적용하는 것(OS는 모름)
  • 1개라도 lock-unlock을 하지 않으면 race condition이 발생할 수 있다.
  • lock은 하고, unlock을 하지 않으면 프로그램이 정지된다.

Condition variables

  • mutex를 사용하고 있는 thread 사이에서 synchronization을 위해 사용된다.
  • thread는 mutex lock에서 condition을 기다리는 상황 → 자신이 기다리는 동안 mutex를 잠시 반납하는 것
  • condition이 만족되면 원래 thread에게 signal을 전달하고 wake-up한다.
  • condition variable은 mutex와 한 쌍으로 다닌다.
  • condition을 대기 Queue로 해석하면 된다.

Create/destroy condition variable

/* condition variable creation & destruction */
int pthread_cond_init(*condition, *attr);

int pthread_cond_destroy(*condition);

/* condition attribute creation & destruction */
int pthread_condattr_init(*attr);

int pthread_condattr_destroy(*attr);

pthread_cond_t* condition
pthread_condattr_t *attr
  • condition variable 초기화 방법
    1) static : pthread_cond_t myconvar = PTHREAD_COND_INITIALIZER;
    2) dynamic : pthread_cond_init(*condition, *attr);

Waiting/Signalling Condition Variables

pthread_cond_wait(condition, mutex); 

pthread_cond_signal(condition);

pthread_cond_broadcast(condition);

pthread_cond_t *condition
pthread_condattr_t *attr
  • return : 성공 시 0 / 실패 시 error value
  • wait() : condition이 만족될 때까지 block = 깨워줄 때까지(=signal/broad)
  • condition을 기다릴 때는 mutex를 잠시 반납하고, 다른 thread가 c-s에 들어온다.
  • wake-up 하면 자신이 사용하던 mutex를 lock한다.
  • signal() : condition의 맨 앞 thread를 호출한다.
  • signal을 호출 했을 때, wait하던 thread가 없다면 그냥 호출 종료된다.
  • broadcast() : condition의 thread를 전부 호출한다.
profile
안녕하세요 :) Data/AI 공부 중인 한국외대 컴퓨터공학부 조권휘입니다.

0개의 댓글