Synchronization examples
Bounded-buffer problem
- shared memory에 접근하는 프로세스를 두 가지로 구분
- 데이터를 적는 프로세스 - producer
- 데이터를 소비하는 프로세스 consumer
- producer가 적을 때 consumer가 데이터를 소비하면 안됨
- 하지만, buffer의 사이즈가 유한하기 때문에 consumer가 빠르게 데이터를 소비해주지 않으면 더 이상 데이터를 적을 공간이 없어 producer는 일을 하면 안됨 / consumer도 동일. writer가 빠르게 데이터를 적어주지 않으면 데이터를 소비할 수 없어 일을 하면 안됨
- empty buffer의 수, full buffer의 수, critical section에 대한 mutex 이렇게 3개의 변수로 컨트롤 하면 됨
- 그래서 이 문제는 buffer에 대한 mutual exclusion 뿐만아니라 buffer 상태에 대한 변수들도 동기화 해주어야 함
semaphore full = 0, empty = n, mutex = 1;
do {
P(empty);
P(mutex);
V(mutex);
V(full);
} while(1);
do {
P(full);
P(mutex);
V(mutex);
V(empty);
} while(1);
Readers-Writers problem
- producer-consumer problem과 비슷한데, 이번엔 reader가 데이터를 읽고 남겨두는 상황
- 그러므로 reader가 동시에 여러개 접근해도 상관 없는 상황
- 두 가지 방식이 있음
- reader가 없을 때만 writer가 작성할 수 있게 함
- writer가 오면 reader를 그만 받고 reader가 다 빠져나가면 writer가 작성
- 첫번째 방식은 starvation의 문제가 있을 수 있지만, 처리율은 높음
- 이진 semaphore 변수인 db와 mutex를 선언
- db는 저장되어 있는 critical section에 접근할 때 이를 mutual exclusion 해주기 위한 변수
- mutex는 reader들이 readcount 변수에 접근하는 것을 mutual exclusion 해줌
semaphore db = 1, mutex = 1;
int readcount = 0;
do {
P(db);
V(db);
} while(1);
do {
P(mutex);
readcount++;
if (readcount == 1) P(db)
V(mutex);
P(mutex);
readcount--;
if (readcount == 0) V(db)
V(mutex);
} while(1);
Dining-Philosophers Problem

- 철학자 다섯 명을 원형 테이블에 앉혀 놓고 젓가락으로 밥을 먹게한다.
- 젓가락은 철학자 사이에 하나씩 놓여 총 다섯개가 있다
- 자신의 양쪽에 놓여있는 젓가락을 모두 확보할 수 있을 때 철학자는 밥을 먹고, 밥을 다 먹으면 내려놓음
- 모든 젓가락을 공유 자원이라고 생각하고 접근했을 때, 모든 젓가락을 semaphore로 보호하면 된다
- 하지만 모든 철학자들이 왼쪽 젓가락을 동시에 들면 밥을 먹을 수 없다
- Deadlock
- 해결 방법
- 무조건 양쪽 젓가락을 동시에 들게 만든다
- 홀수자리 철학자는 왼쪽, 짝수자리 철학자는 오른쪽, 이런식으로 드는 순서를 정해준다
- 다섯명을 다 앉히지 않는다
Semaphore의 단점
- 코딩이 어려움
- 코딩을 제대로 했더라고 하더라도, 올바르게 구축했는 지 알기 어려움
- 큰 프로그램을 짤 때 개발자끼리 합의가 쉽지 않음
- 잘못 사용하면 전체 시스템에 마비
Monitor

- ADT(abstract data type) 형식의 monitor class를 제공하여 lock을 제공
- 진짜 class라기 보다는 class와 비슷한
- high level language로 작성됨
- 객체 내부에 private data가 저장되고 이 data를 접근할 수 있는 public method가 제공됨
- monitor는 montior 안에서 동작하는 process가 단 하나라는 것을 보장
- entry queue를 활용함
- montior 내부에 다른 프로세스가 일을 하고 있으면 entry queue에서 대기
- montior에서 프로세스가 빠져 나가면 entry queue에서 한 프로세스가 monitor 내부 method를 호출
- 문제는, montior 내부에서 proces가 실행되다가 조건이 충족되지 못해서 method를 실행하다가 waiting을 해야하는 경우가 있을 수 있다.
- busy waiting을 monitor 내부에서 걸어버리면 병목현상이 발생
- 이를 위해서 condition 변수가 존재
- condition 변수에서 wait을 통해 sleep하고 signal을 통해 깨어날 수 있음
- monitor를 사용할 때 지켜야할 조건
- public method를 호출할 때, method들 끼리 순서 관계가 있을 수 있으니 이를 맞추어서 호출
- private 변수들은 반드시 public method를 통해서 접근
Monitor:Dining-Philosophers Problem

Deadlock
대기중인 스레드들이 대기하고 있는 자원을 다른 대기중인 스레드가 점유하고 있어 결코 다시는 그 상태를 변경할 수 없는 상태
deadlock 조건
deadlock은 아래의 4조건을 모두 만족하면 발생
- Mutual Exclusion
- No preemption
- 어떤 process가 자원을 소유하고 있으면, 자신이 스스로 해당 자원을 포기할 때까지 다른 process는 해당 자원에 접근 불가능
- Hold and wait
- 어떤 process가 다른 자원을 아직 소유하지 못해 진행을 할 수 없더라도, 지금 소유하고 있는 자원은 가지고 있는 채로 기다려야함
- Circular wait
- 기다리고 있는 process들이 원형대기를 이루고 있어야 함
deadlock 처리방법
- Deadlock이 절대로 발생하지 않게 하는 방법
- Deadlock을 허용하고 detection하여 발생하면 recover
- Deadlock 무시
- 껐다 키기
- 대부분의 OS는 이를 채택
- 그만큼 deadlock 발생활귤이 낮기 때문
- 요즘 컴퓨터들은 자원이 풍족해서 웬만하면 자원이 부족하지 않음
- 그리고 deadlock이 발생하지 않도록 관리하기 위해서는 컴퓨터 자원을 사용해야함
prevention
Deadlock이 일어나기 위해 필수적인 조건 4가지를 배웠는데, 이 조건을 없애 deadlock이 아예 발생하지 않도록 하는 것
- Mutual exclusion
- 자원을 공유할 수 없게 하자는 아이디어는 불가능
- 공유 가능 여부는 해당 자원의 특성으로 이미 결정되어 있음
- OS가 관여할 수 있는 일이 아님
- Hold and wait
- 자신이 추가적인 resource를 얻을 수 없으면, 이미 확보한 자원도 가지고 있을 수 없게 하기
- atomic 하게 자원에 접근하도록 하면 됨
- 이러면 resource utilization이 낮아지고, starvation의 위험성이 있음
- No Preemption
- 어떤 process가 resource를 확보할 수 없어 기다리게 되면, process의 강제로 자원을 뺐자
- hold and wait은 허용하는데, 다른 process가 resource가 필요하면 바로 빼았길 수 있음
- 결과적으로 생각해보면 hold and wait과 크게 다를게 없기 때문에 문제점을 공유한다
- 그리고 추가적으로 그럼 빼았긴 process는 재시작을 해야하는데 이것이 큰 overhead
- Circular Wait
- resource 마다 번호를 정하고 번호가 낮은 resource부터 확보를 해야 다른 resource를 확보할 수 있게 하는 방식으로 circular wait을 구현할 수 있음
- 이런식으로 구현하면 반드시 1번 프로세스부터 n번 프로세스 까지 자신이 기다리는 resource를 크기 별로 나열 했을 때, pn → p1을 기다리는 상황이 절대 생기지 않음
- 이것도 지금 확보 가능한 resource를 특정 이유때문에 점유할 수 없으므로 utilization 감소
- 즉, 전체적으로 low resource utilization과 reduced system throughput을 발생시켜 안좋음
avoidance
Deadlock의 4가지 조건을 모두 허용하는 대신에 동작과정에서 deadlock이 발생하지 않도록 제어
- safe하지 않은 상태로 가는 행위로 모두 차단하는 방식으로 작동
- process가 OS에게 자원을 요청하면, 지금 당장 resource 할당이 가능하더라도 deadlock이 발생할 가능성이 있다면 자원을 나누어 주지 않음
- 그래서 미래에 deadlock이 발생할 지 예측할 수 있어야 함. 이를 위해 정보를 가지고 있음
- 각 process마다 resource type 별로 최대로 사용할 resource maximum을 선언하게 함
Safe State
Deadlock이 발생할 수 없는 안전한 상태
- 모든 process가 다 종료될 수 있는 process 종료 sequence가 존재하는지로 안전한지 판단
- n개의 process가 이미 확보한 자원과 종료된 process가 반납하는 resource양을 합하여 일을 끝낼 수 있는지 모든 경우의 수를 따져봄
- 이렇게 모든 process 가 끝날 수 있는 sequence가 있으면 safe state

- safe state면 절대로 deadlock이 발생하지 않음
- safe state가 아니면 deadlock이 발생할 가능성이 있음
- 왜냐면, saft state는 엄청 보수적으로 가정했기 때문
- 항상 모든 process가 resource를 max로 사용한다고 가정했음
- avoidance는 최악의 상황을 가정해서 항상 안전한 길로만 가는 소심한 방법
Avoidance in Single instance of a resource type
- RAG(resource allocation graph)를 그려서 직접 확인해봄
![업로드중..]()
- claim edge: 지금 사용하는 것이 아닌 사용할 예정인 데이터를 점선으로 가리킴
- request edge: 실제로 resource 달라고 요청. 실선으로 가리킴
- assignment edge: request를 실제로 할당하면서 화살표 방향 변경
- assignment edge는 사라지면서 edge가 아예 사라지는게 아니라 claim edge료 변경됨. 언제 또 사용될 지 모르기 때문
- 이 그래프를 통해 request를 assign 했을 때 cycle이 생기는 지 확인해서 cycle이 생기면 resource를 할당하지 않음

Avoidance in Multiple instance of a resource type
Banker’s Algorithm
- 가정
- 모든 process는 resource type별로 최대로 사용할 instance 수를 명시해야함
- 어떤 process가 resource 달라 요청했어도 받지 못하고 기다릴 수 있음 (safe state 아닐경우)
- 어떤 process가 자기가 필요로하는 모든 resource를 받았으면 일을 끝내고 유한한 시간 내에 resource를 반납해야 함
- 자료구조
- Available[i]
- 각 종류별로 가용한 자원의 개수를 나타내는 vector
- Max[i,j]
- process i가 사용하는 최대 resource j
- allocation[i,j]
- process i가 사용하고 있는 resource j
- need[i,j]
- process i가 추가로 필요로 하는 resource j
- need[i,j] = Max[i,j] - allocation[i,j]
- 알고리즘
- work 배열과 finish 배열을 만듦
- work 배열은 available과 동일
- finish배열은 process i가 일을 끝냈는지 저장. 처음에 모두 false
- 자원을 나눠받을 process 하나를 선택
- finish[i] = false 이고 Need[i] ≤ work
- 존재하지 않으면 4단계로 이동
- process가 선택 되었으면 해당 프로세스에게 모든 자원을 줘서 일을 끝냄
- work += availalbe → 프로세스가 끝났으니 자원 반납
- finish = true → 끝이 났음
- 2단계로 이동
- 4단계에 도착하면 안전하지 않음
- 모든 finish[i] = true가 아니면 sequence가 존재하지 않는거임
detection
Deadlock이 발생하기 전까지 아무것도 안하다가, 현재 deadlock이 발생했는지 따지는 것
recovery
- Deadlock에 관여된 process를 아예 죽임
- deadlock에 관여된 모든 process를 다 죽임
- 하나씩 죽여보기
- priority, 얼마나 오래 계산했는지, resource 양 등을 기준으로 삼음
- Deadlock에 관여된 process로 부터 자원을 강제로 빼았음