2023. 9. 26. 06:07ㆍ전공/운영체제
컨디션 변수
스레드 실행 중간 조건 검사
- 부모 스레드가 작업을 시작하기 전 자식 스레드가 작업을 끝냈는지 알고 싶다면?
- 회전(spin) 기반 공유 변수 활용
- but 바쁜 대기 문제가 남음
컨디션 변수(Conditional variable)
- 일종의 큐 자료 구조
- 어떤 실행의 상태(또는 어떤 조건)가 원하는 것과 다를 때, 조건이 참이 되기를 기다리며 스레드가 대기할 수 있는 큐
- 스레드의 바쁜 대기 문제를 해결할 수 있음
pthread_cond_t c;
- 컨디션 변수 c 정의]
pthread_cond_wait(pthread_cond_t *c, pthread_mutex *m)
- 스레드가 스스로를 재우기(sleep) 위하여 호출
- mutex lock변수 m의 락을 해제하고, 스레드를 잠재움
- 다른 스레드로부터 시그널을 받으면 락을 다시 걸고 리턴됨
pthread_cond_signal(pthread_cond_t *c)
- 조건이 참이 되길 기다리며 잠자고 있던 스레드를 깨우기 위해 호출
만약 상태 변수 done을 정의하지 않는다면?
for(int i = 0; i < 1000000; i++); 를 추가하게 되면 thr_join() 함수가 실행되기 전에 c스레드가 child함수를 실행시키면서 thr_exit()함수가 먼저 실행되게 되어 pthread_cond_signal(&c)를 실행하지만 c는 sleep상태가 아니므로 그냥 지나가게 된다. for문이 끝난 후 thr_join()함수가 실행되어 pthread_cond_wait(&c, &m)이 실행되고 c가 sleep상태가 되지만 pthread_cond_signal(&c) 함수가 이미 실행된 후이므로 sleep 상태의 c를 깨워줄 signal함수가 없어 c는 계속 sleep상태로 머문다. c가 계속해서 sleep상태이기 때문에 main 함수는 thr_join() 이후의 코드들을 실행할 수 없어 위와 같은 문제가 발생한다.
생산자/소비자(유한버퍼) 문제
생산자/소비자(producer/consuemr) 문제
- 유한 버퍼(bounded buffer) 문제라고도 함
- 여러 개의 생산자 스레드와 소비자 스레드가 존재
- 생산자 스레드는 데이터를 만들어서 버퍼에 넣음
- 소비자 스레드는 버퍼로부터 데이터를 꺼내어 사용
- 예시 1: 멀티 스레드 웹 서버
- 생산자 스레드는 HTTP request를 작업 큐(유한버퍼)에 삽입
- 소비자 스레드는 큐에서 request를 꺼내어 처리
- 예시 2 : 파이프 명령 grep foo file.txt | wc -l
- 두 개의 프로세스 grep과 w 가 병행 실행
- grep의 표준 출력 결과는 wc의 표준 입력으로 전달
- grep은 생산자, wc는 소비자
put() 및 get() 루틴
- put() : 공유 버퍼에 값을 넣는 루틴
- get(0 : 공유 버퍼로부터 값을 꺼내는 루틴
임계영역을 고려하지 않은 생산자/소비자 구현 코드
컨디션 변수를 적용한 생산자/소비자 구현 코드
소비자 스레드가 2개 이상이라면?
if문 대신 while문을 적용한 생산자/소비자 구현 코드
소비자 스레드가 2개이므로 하나의 소비자 스레드가 wait상태인 다른 소비자 스레드에게 pthread_cond_signal() 함수를 사용하여 깨울 수 있고 if문을 사용하여 count 상태를 한 번만 확인하기 때문에 위와 같은 문제가 생긴다. 예를 들어 c1과 c2스레드가 wait상태일 때 p가 뮤텍스 락을 얻고 put()을 수행하여 count = 1이 되고 pthread_cond_signal(&cond, &mutex)을 호출하여 c1이 깨어난다면, c1은 get()을 수행하여 count = 0이 되고 pthread_cond_signal(&cond ,&mutex)을 호출하여 c2가 깨어나게 된다. 이때 c2에서 if(count == 0) 조건문은 이미 조건 확인이 끝난 상태이므로 c2는 if문을 빠져나와 get()을 수행하게 되고 이 때 count = 0인 상태이므로 assert(count == 1)을 했을 때 에러가 발생하게 된다.
두 개의 컨디션 변수를 사용하는 생산자/소비자 구현 코드
세마포어 구현
세마포어(Semaphore)
- 정수 값을 갖는 객체
- 두 개의 루틴, sem_wait()와 sem_post()로 조작
- 헤더파일 : semaphore.h
sem_t s;
세마포어 변수 s
int sem_wait(sem_t *s)
- 세마포어 변수 s를 1만큼 감소
- 세마포어 변수 s가 음수라면 wait
int sem_post(sem_t *s)
- 세마포어 변수 s를 1만큼 증가
- 대기 중인 스레드가 1개 이상 있다면, 스레드 하나를 깨움(wake up)
이진 세마포어(락)
- 세마포어 값은 0 또는 1이 됨
- sem_wait() 함수와 sem_post() 함수로 임계영역을 둘러싸는 단순한 구조
- 스레드 Trace : 세마포어를 사용하는 단일 스레드
- 스레드 Trace : 세마포어를 사용하는 두 개의 스레드
조건 체크를 위한 세마포어
- 특정 조건이 참이 될 때까지 대기하는 스레드 코드 구현
- 세마포어를 컨디션 변수와 유산한 용도로 사용
- 스레드 Trace : 자식 스레드를 기다리는 부모 스레드
Reader and Writer문제
Reader and Writer문제
- 다수의 reader와 wrtier threads에 의해 데이터가 공유됨
- 한 번에 오직 하나의 writer만이 공유 데이터에 접근 가능
- 한번에 다수의 reader가 공유 데이터에 접근 가능
- 공유 데이터에 임의의 reader가 접근한 경우 다른 reader 접근 가능
- 공유 데이터에 임의의 reader가 접근한 경우 다른 writer 접근 불가
Reader and Writer를 위한 세마포어
- sem_t lock
- reader스레드가 writelock을 획득 혹은 해제하는 작업이 원자적(atomic)으로 수행되는 것을 보장하기 위한 락
- sem_t writelock
- 임계 영역에 진입한 스레드의 유무를 나타냄
- 공유 데이터에 대해 한번에 하나의 writer스레드만 접근하도록 허용하는 락
- writer스레드가 writelock을 획득하지 않은 상황에서는 공유 데이터에 대해 다수의 reader스레드가 접근할 수 있음
- writer스레드가 writelock을 획득한 상황에서는 다른 write스레드 및 reader스레드 누구도 공유 데이터에 접근할 수 없음
- int read_count
- 공유 데이터에 접근한 reader스레드의 개수
- 공유 데이터에 접근한 reader스레드의 개수
'전공 > 운영체제' 카테고리의 다른 글
메인 메모리 관리 (0) | 2023.09.26 |
---|---|
데드락 (0) | 2023.09.26 |
동기화(Synchronization) (0) | 2023.09.16 |
CPU 스케쥴링 (0) | 2023.09.16 |
저수준에서의 프로세스 관리 (0) | 2023.09.16 |