# Background
- Process Synchronization이란?
: 여러 개의 프로세스가 shared resource를 동기화하지 않고 접근했을 때 발생할 수 있는 문제이다.
=> 쉬운 예로, too much milk problem을 들 수 있는데, 한 사람이 집에 우유가 없는 것을 발견하고, 이미 사러 갔는데, 다른 사람이 알지 못하고 또 다른 우유를 사와서 우유가 필요없이 너무 많이 생기는 문제가 발생한다.
: 이는, 두개 이상 프로세스를 sync하지 않고 접근해서 발생할 수 있는 문제와 비슷하다.
=> 이를 해결하기 위해, 실제 프로그램 상에서는 locking mechanism을 사용한다.
: too much milk problem에서는 이를 냉장고를 잠가버려서 두번째 사람이 확인을 못하고 멈춰있는 비유할 수 있는데, 이는 이미 한 프로세스가 공유자원을 차지하고 있으면, 다음 프로세스 수행 자체를 막아서 동시에 공유자원을 사용할 수 없게 하는 것과 같은 원리라고 볼 수 있다.
# 프로세스 동기화가 안될시 결과는?
A: Race condition이 발생할 수 있다.
: race condition이란 결과값이 달라지는 현상을 말하는데, 여러 프로세스가 shared data에 접근하는 환경에서 프로그램 수행 결과가 접근 순서에 따라 바뀔수 있음을 의미한다.
=> 이는 매우 중요한 이슈이다. 결과가 달라지면 data consistency가 위배되기 때문이다. 값이 다르게 나온다는 것이 가장 치명적인 점으로, 반드시 Data consistency를 보장해야 한다.
EX) Producer-consumer process가 존재할 때
=> count++ 과, count-- 는 각각 세가지의 step으로 이루어져 있다. 이를 수행하는 순서에 따라 count값이 달라질 수도 있다 : race condition이 발생할 가능성이 존재한다.
각 operation이 atomic하게 진행되었을때, 원래 결과는 5에서 1이 더해져서 6이되고, 또 1을 빼서 5가 되어야 한다.
그렇지만, 각 operation이 동기화되지 못하고 마구잡이로 실행되었기 때문에 Race condition이 발생할 가능성이 있다.
<Race condition 발생하는 연산의 예시>
1) count값이 register1 값에 대입되고, register1값이 1 증가하였지만, register1값이 count에 대입되기 전에 consumer process로 context switch가 되었다. 따라서 register2의 값은 5가 된다.
2) register2의 값이 1 minus된 상태에서 producer process로 context swtich가 된다. 이때, count값에 register1값이 대입되어서 count가 6이 된다.
3) 마지막으로 consumer process로 context switch가 되어, count에 register2값이 대입되어 마지막 결과가 4가 된다.
=> 따라서, 한 프로세스가 공유자원을 차지하고 있을 동안에는 다른 프로세스가 끼어들지 못하게 Locking mechanism을 사용하게 된다. 이는 context가 atomic 하게 실행하도록 하여 race condition이 발생하지 않도록 한다.
+) Race condition (원하지 않는 결과가 나옴)이 발생하면, 프로그램 수행 순서에 따라 output이 달라질 수 있다. OS는 이를 해결하기 위한 policy가 많이 존재한다.
=> Assembly line에서의 연산은 각각 atomic하지만, C code등의 high level code는 atomic하지 않을 수 있다.
# How to Avoid Race condition?
=> race condition을 예방하는 가장 좋은 방법은 각 연산을 atomic하게 수행하는 것이다. assembly line을 따로따로 연산하지 않고 한번에 수행해야 한다.
=> 이를 가능하게 하기 위해서는 shared 되는 변수인 count를 어떻게 프로그래밍해야 하는가?
: count++ 라는 statement가 끝날 때까지 다른 프로세스가 절대 끼어들지 못하게 해야 한다.
-> 하나의 프로세스만이 공유 변수에 접근할 수 있도록 해야 한다.
#Preemptive Kernel vs. Nonpreemptive kernel
1. Non-preemptive kernel
: race condition에 대한 고려가 필요하지 않다. preemption을 허용하지 않기 때문이다.
2. Preemptive kernel
: preemption을 허용하기 때문에, 여러가지 race condition들을 세심하게 고려해야 한다.
ex) System call 은 모든 프로세스가 공통적으로 호출할 수 있는 함수이다.
만약 A라는 함수에서 System call 수행중일 때 context switch를 허용하게 되면, B라는 프로세스가 진입하여 shared data가 동시에 접근될 가능성이 있다.
# The Critical-Section Problem
: race condition을 해결하기 위해 프로그래밍을 어떻게 해야 할지 formal 하게 모델링한 것이다.
=> n가지의 process들이 공유 데이터에 접근하기 위해 경쟁한다. 각 프로세스들은 critical section이라고 부르는 code segment가 존재하는데, 이는 공유 변수가 접근되는 영역을 말한다.
=> 반복문 형태의 프로그램이라고 가정하고, 중간에 반드시 critical section이 있어야 한다.
그리고 Entry와 Exit section에 프로그램을 추가하여 critical section에 진입하고/ 벗어날 수 있도록 해서
Shared data 때문에 발생할 수 있는 세가지 property를 만족할 수 있어야 한다.
# 따라서, 결과적으로 Entry& Exit section에 코드를 추가하고, 세가지 property를 만족시키는 프로그램을
작성할 수 있어야 하는 것이 관건이다. 도대체 이 세가지 property는 무엇을 말하는 걸까?
< Critical- Section problem을 해결하기 위한 Property>
1. Mutual Exclusion
: critical section에서 어떠한 프로세스가 실행중이면, 다른 어떤 프로세스도 실행돼서는 안된다.
2. Progress
: 프로세스의 선택이 무한정 연기되어서는 안된다. Entry section에서 기다리는 process가 하나 이상 있다면, 반드시 어떤 프로세스는 Critical section으로 진입해야 한다.
3. Bound Waiting
: 다른 프로세스가 critical section에 몇 번만 기다리면 진입할 수 있는지에 대한 횟수의 한도가 존재한다.
=> 프로세스가 무조건 진입할 수 있음을 보장하게 된다.
=>예시로 각 property를 위반하는 경우를 살펴보자.
1. Mutual Exclusion Property
: 앞에서의 producer-consumer process 경우에서 두 프로세스가 shared data영역에 동시에 접근하는 경우를 보았다.
이 경우가 대표적인 mutual exclusion을 위반한 경우이다.
=> 두개 이상의 process가 진입해선 안되고, critical section에 어떤 프로세스가 진입한 이상, context swtich가 발생해서는 안된다. 이를 통해 Race condition 발생 가능성을 막을 수 있다.
=> 각 프로세스를 atomic하게 실행함으로써 각 시점에는 critical section에 오직 하나만의 프로세스가 존재하게 된다.
2. Progress Property
=> Progress property에는 조건이 존재한다.
: Critical section이 비어있을 때 entry section에서 기다리고 있는 process 중에서 셋 중 하나라도 진입해야 한다.
=> 어떤 프로세스도 진입하지 않고 기다리고 있는 위의 경우는 Progress property를 위반하는 대표적인 사례이다.
ex) Progress property가 발생하는 원인에는 entry section에 오직 하나의 프로세스만 진입할 수 있도록 프로그래밍하다 잘못해서 모든 프로세스가 기다리게 만들어 버리는 경우가 있다.
3. Bounded Waiting Property
=> 기다리고 있는 프로세스가 몇 번 정도 기다리면 Critical section에 반드시 진입할 수 있다는 보장이 있어야 한다.
한 프로세스를 무한정 기다리게 하고 다른 프로세스들만 진입하게 하면 bounded waiting property를 위배하는 것이다.
#Peterson's Solution
: 해당 솔루션은 세개의 property 만족하기 위해 제시되었다.
1) Flag는 프로세스가 자신이 공유자원을 쓰고 싶다고 함을 표현하기 위한 변수이다.
2) turn은 어떤 프로세스가 이미 들어가 있는 건 아닌지 확인해주는 변수라고 이해하면 된다.
그렇다면, 해당 Solution이 세가지 Property를 만족하는지는 어떻게 확인할 수 있는가?
1. while (flag[j] && turn==j) line을 살펴보면, 만약 Pi 가 Critical Section에 진입하고 싶어서 flag[i]를 true로 바꾸었지만, 이 상태에서 Pj가 미리 실행되어서 flag[i]가 true가 아니었던 상태에서 Pj가 이미 critical section에 진입을 했고,
pi process에서도 위 turn=j; line을 통해서 flag[j]의 값이 True이고, turn이 j 를 가르키고 있는 상태이기 때문에 Pi process는 기다려야만 한다.
=> turn값이 동시에 i와 j값을 모두 갖는 건 불가능 하기 때문에 Mutual Exclusion property를 자연스럽게 만족한다.
2-1) Pi 가 while loop 에 있으면, Pj 프로세스가 Critical section을 빠져나와서 Flag[j]=false line을 실행하게 된다면, Pi가 while loop를 빠져나오게 된다. 따라서 Pi가 critical section에 진입이 가능하다.
Pj가 갇혔을 때도 역시 Pi가 C.S를 빠져나오면서 Flag[i]를 false로 만들어주기 때문에 Pj가 진입이 가능하다.
2-2) 만약 Pj가 while loop를 실행하고 있다면, 역시, turn이 i를 가르키고 있는 상태이기 때문에 역시 Pi 가 while loop 에서 빠져나와서 pi는 Critical section에 진입할 수 있다.
=> 따라서 Pj가 어떤 line을 실행하고 있든 Pi가 critical section에 진입할 수 있기 때문에 Progress property를 만족한다.
3) Pi process가 while loop 벗어나서 critical section에 진입했다고 가정했을 때, Pj 프로세스는 while loop에 걸쳐있다.
critical section에서 빠져나오면 flag[i]를 false로 지정해준다. 따라서 Pj가 while loop를 벗어나 critical section에 진입할 수 있게 된다.
=>exit section에 특정 프로세스의 flag값을 바꿔줘서 while loop를 벗어날 수 있도록 보장해준다. 따라서 bound waiting property가 성립한다.
+) Shortcomings
1. Busy waiting이 발생할 수 있다.
=> While loop에서 프로세스가 Critical Section에 진입 가능해질 때까지 계속 돌고 있기 때문에 의미 없는 무한정 체크가 반복된다.
2. Implementing 이 어렵다.
3. 오직 두개의 프로세스에서만 사용 가능하다.
#Bathroom
=> Critical section은 오직 하나의 task만들어갈 수 있기 때문에 bathroom에 비교될 수 있다.
그렇지만 누군가는 화장실에 들어가야 하고, 화장실에서 나오면 반드시 들어갈 수 있다는 점에서
Mutual exclusion, Progress, Bounded waiting property를 만족한다.
=>이러한 properties를 사용하기 위해 어떤 메카니즘을 사용할 수 있을까?
1) Binary Semaphore(Mutex)
: Mutex는 0,1두가지 값만 갖는 binary semaphore로, key와 비유될 수 있다. 따라서 Mutex를 소지하고 있는 (1)상태의
task만 Critical section에 진입할 수 있도록 허용하게 된다.
=> task가 수행을 마치면, Key를 다음 사람에게 넘겨줌으로써 Progress property를 만족할 수 있게 된다.
2) Waiting Arrray
=Queue로, bound를 보장하기 위해서는 Mutex와 waiting array 둘다 가져야 한다.
=> 프로세스 순서대로 줄이 서있어야 순서대로 들어가는 Bounded waiting property가 보장된다. 아니면 새치기가 가능해져서 순서가 뒤죽박죽된다.
# Hardware support for Synchronization
1. Peterson's algorithm
: Entry section에 3줄, exit section에 1줄의 코드를 통해서 각종 property를 만족 할 수 있게 한다.
=> Busy waiting이 발생하고, 구현이 어렵다는 점에서 잘 사용되지는 않는다.
2. Uniprocessors
-> 가장 강력하게 context switch를 막는 방법이다. interrupt 자체의 발생을 막아서 preemption을 허용하지 않음으로써 아예 다른 프로세스가 중간에 끼어들지 못하게 할 수 있다
: 그렇지만 Multiprocessor system에 비해서는 너무 비효율적인 부분이 존재한다.
Message passing delay도 발생할 수 있고, 모든 CPU에게 interrupt disable 메세지를 전달해야 한다는 점에서
overhead가 발생할 여지 가 있어서 잘 사용되지 않는 방법이다.
3. Atomic Hardware instruction
=> 현대에서는 가장 많이 사용되는 기법이다. hardware instruction level에서 atomic한 instruction이 몇개 지원되게 된다. : 이를 제공하여 효과적인 sync가 제공 가능하다.
- Test memory word and set value, swap, atomic variable을 통해서 구현될 수 있다.
-1) TestAndSet()
=>target이 false일때, target을 true로 바꿔주게 된다. 그렇지만 return value값은 원래의 original value값이다.
따라서 target 이 true일때는 target과 return value값 둘다 true로 리턴된다.
=> Target이 원래 false일때는 다음 code가 실행되지만, 다음 access는 block되게 된다.
Target이 true이므로, target과 rv값 모두 true가 되므로 해당 프로세스는 block된다.
만약 Testandset에서 target값이 false면 다음 코드를 실행하게 되고, target값이 true라면 critical section이후에
target=false 코드를 통해서 while loop에서 빠져나와서 critical section에 진입하게 된다.
=> Peterson's solution에 비교했을때에 비해 훨씬 간결하다.
=> Mutual exclusion과 progress property를 만족하게 된다.
+) 만약 Testandset instruction이 atomic하지 못하다면?
=> lock이 false인 사이에 context switch해서 다음 프로세스가 read된다면 lock이 true로 바뀌기 전에 다음 프로세스의 lock값도 false가 된다. 따라서 프로세스 두개가 다 false가 되므로 mutual exclusion을 위배한다.
- Another atomic operation
=> a, b를 swap하는 instruction도 존재하게 되는데,
=> key를 true로 만들어주는 instruction을 미리 실행시켜 준 다음에, lock이 false라면 while 문에서 key와 lock이 바뀌게 되어 lock 값이 true가 되고, key값이 false가 되어 while문을 빠져나오게 된다.
그렇지만 lock 값이 true로 바뀌고 난 다음엔 swap하더라도 lock과 key값이 모두 true이기 때문에 아무리 SWAP하더라도 while문에 갇히게 되고, 이미 실행중인 프로세스가 빠져나와 lock값을 false로 만들기 전까지는 대기상태에 있다.
=> 앞선 솔루션( TestandSet, Swap) 들은 프로세스간의 순서가 없이 뒤죽박죽 실행되기 때문에 어떤 프로세스는 영원히 실행되지 않을 수도 있다. 따라서 bounded waiting property를 만족하기 위해 waiting array를 적용하게 된다.
=>D 프로세스가 얼마나 기다리면 critical section에 진입할 수 있는지에 대한 bound가 존재해야한다.
: 이는 scheduler가 결정해야 하는 문제이다.
#Atomic Variables in Linux
=> 리눅스에서는 atomic variable이라는 리눅스 커널 안에 있는 변수가 존재한다. (user level에서 사용은 불가능)
: kernel은 race condition이 많이 발생할 수 있기 때문에 , atomic_xxx instruction을 통해서 각 operation을 atomic하게 수행한다. -> atomic_set(&v,4) 라는 instruction을 atomic하게 수행함으로써 race condition을 없앤다.
: 이를 통해 mutual exclusion property를 보장할 수 있다.
#Semaphore
Semaphore S-> 는 integer variable로, process synchronization에서 가장 효과적인 방법이다.
: Semaphore란 기찻길에서 있는 flag를 의미하고, critical Section앞에 있는 flag를 생각하면 된다.
=> 주로 두가지의 standard operation이 있는데, 바로 Wait()와 Signal()함수이다.
:integer 변수에 접근하기 위한 두가지 함수로, semaphore가 대기상태에 빠지게 하고, 빠져나오게 해주는 역할을 한다.
# Semaphore의 종류
- Counting semaphore
: semaphore의 변수값 제한이 없고, 10,11,---등등 원하는 만큼 value값을 가질 수 있다.
- Binary semaphore (Mutex)
: semaphore가 오직 0,1의 두가지 값만 가질 수 있다. 구현하기는 훨씬 쉽다.
=> Mutex에서는 Mutual exclusion을 반드시 제공한다.
=> 한 프로세스가 critical section에 진입했을때는 이미 sem의 값이 0이므로, 다른 프로세스는 기다리게 된다.
만약 그 프로세스가 critical section을 벗어나면, S값을 1로 만들어주고, 기다리고 있던 프로세스는 wait section에서 1ㅏ로 0으로 감소시키고 critical section에 진입하게 된다. (Mutual exclusion 보장하기 위해서는 Mutex만 써야한다)
: Wait-> Signal 순으로 함수가 실행되어야 한다.
#Semaphore with While loop
=> Semaphore를 활용해서 효과적으로 synchronization property를 보장하게 된다.
: 그렇지만, While문을 사용함으로써, Spin lock , busy waiting이라는 문제점이 발생한다.
: Spin lock은 루프 형태로 synchronization을 제공하고, 계속 critical section으로 진입할 수 있는 권한이 존재하는지 체크한다. 따라서 바쁘긴 하지만 막상 하는일 없이 기다리기만 한다.
=> 그렇다면 이 프로세스가 CPU를 사용하지 않느냐 (Process가 running state인가?) 하면 그것도 아니다.
: Wait 함수의 while loop를 호출한 프로세스는 scheduler가 주시하고 있고, 해당 프로세스를 수행해야 하는 개체로 여긴다. = 따라서 CPU를 사용하고 있는 상태인 것이다.
A) 그렇다면, CPU를 사용하면, Semaphore를 만들기 위해서 block하는 instruction으로 while loop를 사용하여 비효율적으로 동기화하는것보다, Process의 state자체를 waiting state로 전환시켜서 대기 상태로 빠지게 한다.
=> 따라서 해당 프로세스는 아예 수행 조차 안되며, candidate process에도 끼지 못하게 된다.
#Semaphore without busy waiting
: 기다리는 프로세스를 waiting queue에 집어넣고, 프로세스가 waiting queue에 존재한다면 해당 프로세스의 process state를 waiting 으로 전환해준다. 이때, 두가지의 data item이 필요하다
- Semaphore의 value값과, waiting queue list의 다음 프로세스를 가리키는 포인터가 필요하다.
- 그리고 두가지 operation을 실행하게 된다.
1) Block (wait함수)
: 특정 프로세스를 waiting queue에 집어넣어주고, waiting 상태로 전환해주는 operation이다.
=> wait함수에서 Semaphore의 값이 0보다 작으면, waiting list에 집어넣고 프로세스를 block한다.
2) Wakeup (signal함수)
: signal 함수에서 먼저 진입한 프로세스가 Critical Section에서 벗어날 경우, Semaphore값을 1 증가시키고 Semaphore의 값이 0보다 작거나 같을 경우 Waiting queue의 맨앞에 있는 프로세스를 깨워서 Ready queue에 집어넣어준다.
=> 만약 P1이 Semaphore값이 1일 경우에, Semaphore를 1감소시키고 0이 되어 Critical section에 진입한다.
그리고, 그뒤에 P2가 진입을 시도하여 wait 함수에 들어가면, Semaphore값이 -1이 되므로 block이 된다.
따라서 P2가 waiting queue로 들어가며 대기상태에 빠져서 CPU가 전혀 사용되지 않는다.
그이후에, P1가 Critical section에서 빠져나오면서, Signal함수에서 semaphore값을 1 증가시켜 0으로 만든다.
따라서 P2가 wakeup되면서 ready queue state로 들어가고, 그 다음 Critical section으로 진입하게 된다.
따라서 반드시 Mutual Exclusion property와 Progress property는 만족하게 된다.
( Semaphore값이 -1의 값도 가질 수 있다)
struct semaphore {
int count;
queueType queue;
};
void semWait (semaphore s) {
s.count--;
if (s.count < 0) {
/* 이 구역으로 들어왔다는 것은 현재 프로세스(혹은 쓰레드)가 공유 자원에 접근할 수 없다는 것을 의미*/
/* 요청한 프로세스를 s.queue에 연결 */
/* 요청한 프로세스를 블록 상태로 전이 시킴*/
}
}
void semSignal (semaphore s) {
s.count++;
if (s.count <= 0) {
/* count가 0보다 작거나 같다는 것은 대기하고 있는 프로세스(또는 스레드)가 존재한다는 것을 의미*/
/* s.queue에 연결되어 있는 프로세스를 큐에서 제거 */
/* 프로세스의 상태를 실행 가능으로 전이시키고 ready list에 연결 */
}
}
* 실제로 Sem_wait, Sem_post와는 약간 다른 것을 기억하자!
# sem_post(sem)
: semaphore 객체가 0일때, 1 증가시켜준다.
# sem_wait(sem)
: semaphore 객체를 원자적으로 1 감소시키는 함수인데, semaphore가 0보다 큰 숫자를 갖고 있으면 1을 감소시키고, 0일 경우에는 semaphore 객체가 증가할 때 까지 기다린다. (0,1만 거의 갖게 된다고 본다)
#semaphore의 핵심은, 프로세스를 waiting 상태로 전환하여, Critical section에 진입하기 위해 기다리고 있는 프로세스들을 list형태로 관리하는 프로세스가 Blokc operation이고, waiting queue에서 ready state로 전환하는 operation이
wakeup operation이라는 것을 기억하는 것이다.
=> Lock이 매우 짧은 시간동안만 된다고 예상한다면, Spinlock을 이용한 semaphore도 효과적이다.
: 만약 block되는 시간이 짧다면, Waiting state로 전환하는 overhead가 더 클수 있다
=> 하지만, Spinlock을 제외한 semaphore는 lock되는 시간이 긴 경우에, 훨씬 효율적이다.
: Waiting 상태에서 오래 기다릴 경우에 굳이 While loop를 돌면서 CPU를 사용할 이유가 없다.
+) Semaphore는 bounded waiting time property를 만족하지 않을 수도 있다.
:여러개의 프로세스를 한번에 실행시킨다면, 어떤 프로세스는 영원히 실행되지 않을 수도 있다.
(Deadlock과 Starvation이 발생할 가능성도 존재하기 때문이다.)
# Monitors
- Semaphore에도 단점이 존재한다.
: 구현하기 어렵고, 정확성을 입증하기도 어렵고, 프로세스끼리의 협력을 필요로 하고, 함수를 약간만 잘못 이용해도
전체적인 시스템에 영향을 끼치게 된다.
=> semaphore에서 signal 함수를 두번 쓰면, Mutual Exclusion property가 위배된다.
=> 또, semaphore를 두번 wait하게 되면 deadlock 상태가 발생하게 된다.
- 따라서, Monitor라는 개념을 적용해서
: Wait, signal함수를 프로그래머가 정의하지 않고, 훨씬 이해하기 쉬운 버전으로 사용한다.
: Mutual exclusion을 보장하기 위해서는 모니터에서 하나의 프로세스만이 특정 시점에서 active해야 할 것이다.
https://copycode.tistory.com/83
=> Monitor에서는 오직 하나의 프로세스만이 active해질 수 있다.
: 다른 프로세스들을 입장 queue에 넣고 프로세스가 모니터에 들어갈 수 있도록 기다려야만 한다.
: 주로 shared data 영역, 각 operation=procedure 부분, 그리고 초기화 코드 부분으로 나눠져 있다.
: monitor로 define된 procedure들은 monitor 내에서 선언된 변수에만 접근할 수 있다.
=> 하나의 프로세스만 active하고, 다른 프로세스들은 기다리게 할 수 있도록 하는 변수: Condition variable이다.
: Condition variable과 관련된 두가지 operation이 존재한다. x.wait(), x.signal()으로 주로 사용된다.
x.wait() 함수:
=> x라는 condition에 관련된 함수로써, wait operation을 호출한 프로세스가 condition variable을 기다리는 queue에 insert되도록 한다
x.signal() 함수
: Queue에서 하나의 프로세스를 깨워서 모니터 안으로 진입하도록 한다.
=> Condition variable에 접근할 수 있는 wait, signal함수가 반드시 Define되어야 한다.
<실제로 모니터를 구현해본 API>
=> Monitor를 하나 선언하여, busy라는 shared data와 condition 변수를 선언한다.
- Acquire 함수에서는 ,현재 시간을 인자로 받아서, 만약 이미 monitor가 사용중이라 busy 값이 true라면, time인자를 wait하게 만든다.
- Release함수에서는, Busy값을 false로 바꿔주고, wait 함수 인자 중에 시간값이 가장 적은 프로세스, 즉 가장 빨리 들어와 큐의 앞쪽에 위치하는 함수를 깨워주는 역할을 한다. 그 이후에 깨어나 Ready 상태가 된 프로세스는 acquire로 들어가서 실행되고, busy값을 true로 만들어 다른 프로세스를 block한다.
=> Wait/ Signal 대신에 acquire/release를 사용하고, Mutual exclusion property를 보장한다.
+) 종종 time 인자를 넣는것이 부적절할 수도 있다.따라서 대신에 priority number를 의미하는 c를 집어넣고,
우선순위 에 따라 가장 작은 number를 갖는 프로세스를 wakeup 시켜줄 수도 있다.
'Computer Science > Operating system' 카테고리의 다른 글
Chapter 8. Deadlock (0) | 2020.06.05 |
---|---|
Chapter 7. Classic Problems & POSIX API (0) | 2020.06.05 |
Ch 5-3) Process scheduling (0) | 2020.05.31 |
Ch 5-(1),(2) Process Scheduling (0) | 2020.05.16 |
ch4 - Threads& Concurrency (0) | 2020.05.04 |