![]() |
|---|
| - Mutual Exclusion 보장 |
| - 교대로 작업하기 때문에 상대 프로세스가 fail 하거나, critical section에 도달하는 데에 오랜 시간이 걸리거나, 더 이상 critical section 진입을 시도하지 않는다면, critical section 진입이 불가할 수 있다. |
| - Busy-waiting 발생: turn 값이 상대 값일 때 프로세서를 할당 받는다면 while 문을 반복하는 데에 시간을 다 쓰게 된다. |
![]() |
|---|
| - Mutual Exclusion 보장 X |
| - flag 값이 둘 다 false 인 상태에서 while 문 탈출 직 후에 프로세서가 상대에게 넘어가면, 둘 다 critical section에 진입할 수 있는 상황이 발생한다. |
![]() |
|---|
| - Mutual Exclusion 보장 |
| - Deadlock 발생 가능: P0의 flag[0] = true 수행 직후 P1의 flag[1] = true 가 수행된다면 프로세스 둘 다 while 문 탈출이 불가능해진다. |
| - 교대로 작업하는 것이 아닌 상대 flag가 false 이기만 하면 연속 재진입이 가능하다. |
| <증명> |
| 1. P0와 P1이 동시에 critical section 에 진입했음을 가정한다. |
| 2. P0가 critical section에 진입하려면 flag[0] = true, flag[1] == false 확인 작업이 필요하다. |
| 3. 이러한 상황에서 P1이 critical section에 진입하려면 P0의 flag[0] = true 가 수행되기 전에 flag[1] = true, flag[0] == false 확인 작업이 필요하다. |
| 4. 이때 P0의 flag[1] == false 확인이 모순이 된다. |
| 5. 따라서 Mutual Exclusion 이 보장된다. |
![]() |
|---|
| - Mutual Exclusion 보장 |
| - Deadlock 발생 X |
| - Livelock 발생 가능: while 문을 실행하고 있는 동안에 상대편의 flag 값이 바뀔 가능성이 있기 때문에 while 문 탈출이 가능하다. |
| - 교대로 작업하지 않는다. |
![]() |
|---|
| [Dekker's Algorithm] |
| - Mutual Exclusion 보장 |
| - turn 값이 상대편 값이면 내 flag 값을 false 로 변경하여 차례를 양보한다. |
| - Deadlock, Livelock, Starvation 발생 X |
| - 상대 프로세스가 critical section에 진입할 의사가 없다면 현재 프로세스는 대기 없이 바로 진입 가능하다. |
| < 둘 다 critical section에 진입하려는 상황에서 turn == 0 > |
| - P0은 while (flag[1]) 을 반복한다. |
| - P1는 turn 값이 0임을 확인 후에 flag[1] = false 를 수행하고 while (turn == 0) 을 반복한다. |
| - P1이 Timeout 되고 P0가 실행 됐을 때 flag[1] == false 를 확인하고 while (flag[1]) 을 탈출하면서 critical section 에 진입하게 된다. |
| < 둘 다 critical section에 진입하려는 상황에서 P0가 먼저 진입했을 때, 작업 후에 또 다시 P0가 진입하는 경우 > |
| - turn == 0 일 때, P1은 flag[1] = false 수행 후 while (turn == 0) 반복한다. |
| - P1의 Timeout 후에 P0는 flag[1] == false 를 확인하고 critical section 을 수행한다. |
| - critical section 작업을 끝낸 후에 재진입을 시도하면 flag[1] == false 이기 때문에 대기 없이 바로 수행 가능하다. |
| - 재진입 전에 turn 값은 1로 변경되고, P0가 계속 실행되는 동안 turn 값의 변화는 발생하지 않는다. |
| - 이후 P0가 어떤 지점에서 실행 중단 되든 간에 P1는 while (turn == 0) 을 탈출하고 flag[1] = true 수행 후 flag[0] 이 false 가 되기만을 기다린다. |
| - P0는 turn == 1 을 확인하여 flag[0] = false 수행 후 while (turn == 1) 반복한다. |
| - 최종적으로 P1의 critical section 진입이 가능해지고 Starvation 이 발생하지 않는다. |
| < while (flag[1]) 반복 -> while (turn == 1) 반복 상황 > |
| - 불가능 |
| - while (flag[1]) 반복 조건: flag[1] == true, turn == 0 |
| - while (turn == 1) 반복 조건: turn == 1 |
| - P0의 while 문 내에서 turn 값이 바뀔 수 없고, P1에서는 turn = 1 코드가 없기 때문이다. |
| < while (turn == 1) 반복 -> while (flag[1]) 반복 상황 > |
| - 가능 |
| - while (turn == 1) 반복 조건: turn == 1 |
| - while (flag[1]) 반복 조건: flag[1] == true, turn == 0 |
| - P1의 critical section 작업 완료 후 turn = 0 까지만 수행되고 프로세서가 넘어가면 가능하다. |
![]() |
|---|
| [Peterson's Algorithm] |
| - Mutual Exclusion 보장 |
| - 교대 진입이 불필요하고, 다른 프로세스가 critical section 진입 의사가 없으면 대기 없이 바로 진입 가능하다. |
| - Deadlock, Livelock, Starvation 발생 X |
| - 둘 다 critical section에 진입하려는 상황에서, 먼저 turn 값을 상대 값으로 바꾼 프로세스가 먼저 critical section 에 진입하게 된다. |
| - 둘 다 critical section에 진입하려는 상황에서, 한 프로세스의 critical section 수행 후에 재진입이 불가능하다. (turn) |
| <증명> |
| - P0의 critical section 진입 조건: flag[1] == false OR turn == 0 |
| 1. flag[1] == false |
| - P1의 flag[1] = true 수행 전에 P0가 실행되면 critical section 진입 가능 |
| - P1의 진입 시도에서 while (flag[0] && turn == 0) 에서 걸리기 때문에 critical section 진입 불가능 |
| 2. turn == 0 |
| - P0의 turn = 1 먼저 수행 후 P1의 turn = 0 수행 |
| - P0 critical section 진입 |
| - P1의 진입 시도에서 while (flag[0] && turn == 0) 에서 걸리기 때문에 critical section 진입 불가능 |
![]() |
|---|
| [Compare & Swap Instruction] |
| - bolt == 0 일 때 가장 먼저 compare_and_swap() 을 실행한 프로세스가 critical section 에 진입한다. |
| - 동시에 여러 프로세스가 bolt 값에 접근하는 것이 불가능하기 때문에 여러 프로세스가 동시에 실행되는 상황에서도 사용 가능하다. |
| - Mutual Exclusion 보장 |
| - Busy-waiting O |
![]() |
|---|
| [Exchange Instruction] |
| - bolt == 0 일 때 가장 먼저 exchange() 를 실행한 프로세스가 critical section에 진입한다. |
| - 일시적으로 여러 프로세스의 keyi 값이 동시에 0 인 상태가 나타날 수 있다. (한 프로세스의 critical section 및 bolt = 0 수행 후 다른 프로세스가 진입을 시도할 때) |
| - 반복문 없이 여러 critical section을 구현할 때 keyi 값의 초기화가 필수적이다. |
Software Approach, Hardware Instruction 모두 Busy-waiting 이라는 문제점을 가진다.
- Mutual Exclusion 보장
- Deadlock X
- Livelock X
- Busy-waiting X
![]() |
|---|
| [Bounded Buffer] |
| - b 가득 찼을 때: producer 대기 |
| - b 비었을 때: consumer 대기 |
| - in, out 값 때문에 critical section 구현이 필요하다. |
![]() |
|---|
| [3개의 Semaphore를 이용한 구현] |
| - s: critical section을 구현하기 위한 세마포어 |
| - n: 사용 가능한 데이터 개수를 표현하기 위한 세마포어로 버퍼가 비었을 때 consumer를 blocked 시킨다. |
| - e: 버퍼의 빈 자리 개수를 표현하기 위한 세마포어로 버퍼가 가득 찼을 때 producer를 blocked 시킨다. |
| < Producer, semWait(s) -> semWait(e) ? > |
| - 버퍼가 가득 찼을 때, critical section에 먼저 진입한 후에 semWait(e)에서 Blocked 되므로 어떤 consumer도 critical section에 진입할 수 없고, 따라서 producer의 Blocked 상태를 해제할 수 없으므로 Deadlock이 발생할 수 있다. |
| < Consumer, semWait(s) -> semWait(n) ? > |
| - 버퍼가 비었을 때, critical section에 먼저 진입한 후에 semWait(n)에서 Blocked 되므로 어떤 producer도 critical section에 진입할 수 없고, 따라서 consumer의 Blocked 상태를 해제할 수 없으므로 Deadlock이 발생할 수 있다. |
![]() |
|---|
| - 여러 procedure와 지역 변수, 초기화 시퀀스, 컨디션 변수들로 구성된다. |
| < Characteristics > |
| - 지역 변수들은 모니터 안에서만 접근 가능하다. |
| - 프로세스는 모니터 내의 procedure 를 호출함으로써 모니터에 진입한다. |
| - 하나의 프로세스만 모니터에 진입 가능하기 때문에 Mutual Exclusion이 보장된다. |
| < Synchronization > |
| - 모니터에 의해서만 접근할 수 있는 컨디션 변수를 통해 동기화가 이루어진다. |
| - cwait(c): 해당 프로세스는 Blocked 시켜 큐에서 대기하도록 한다. |
| - csignal(c): 해당 컨디션 변수(큐)에 있던 프로세스를 모니터에 진입하게 한다. |
| - 컨디션 변수는 원하는 만큼 생성 가능하다. |
| +) 모니터 내에서 해야 할 작업이 남은 프로세스는 csignal 을 호출하면서 urgent 큐에서 대기하고, 큐에 있던 프로세스는 모니터에 진입한다. |
| +) 컨디션 변수에서 대기하고 있는 프로세스가 모니터 밖에서 대기하고 있는 프로세스보다 우선순위가 높기 때문에 먼저 모니터에 진입하여 작업을 종료한다. |
![]() |
|---|
| - 모니터 자체가 critical section이기 때문에 세마포어 s 를 구현할 필요가 없다. |
| - 세마포어 n, e 대신에 2개의 컨디션 변수를 사용하여 구현한다. |
| - producer의 append(x)와 consumer의 take(x), 그리고 버퍼는 모니터 안에서 구현된다. |
| - count: 세마포어 방식과 달리 critical section 내의 변수로 자유롭게 연산이 가능하다. |
| - Producer: 버퍼가 가득 차 있다면 notfull에서 대기하고 notempty의 consumer를 모니터로 꺼낸다. |
| - Consumer: 버퍼가 비어 있다면 notempty에서 대기하고 notfull의 producer를 모니터로 꺼낸다. |
| +) 세마포어 방식에서는 critical section에 먼저 진입한 뒤에 버퍼의 상태를 확인하면 Deadlock이 발생할 수 있다. 하지만 모니터 방식에서는 발생하지 않는다. 모니터 자체가 critical section으로, 모니터에 진입한 프로세스가 없다면 얼마든지 다른 프로세스의 진입이 가능하고 큐에서 대기하던 프로세스의 Blocked 상태를 풀어줄 수 있기 때문이다. |
![]() |
|---|
| [Semaphore를 이용한 구현] |
| - wsem 큐에서 reader는 대표 한 명만 대기하고, 그 한 명이 critical section에 진입하면 semWait(x) 에서 대기하던 프로세스들도 우르르 진입하게 된다. |
| - readcount: 내가 첫 번째 reader 인지, 마지막 reader 인지를 확인하는 변수이다. |
| - readcount 자체가 공유 변수이기 때문에 readcount 연산을 critical section으로 구현한다. |
| - semWait(x): readcount 연산을 critical section으로 구현하기 위해 사용하고, 첫 번째 reader를 제외한 나머지 reader들이 대기하는 장소이다. |
| - reader가 critical section에 존재하는 상황에서 새로운 reader들이 진입하려고 하면 이미 대기하고 있던 writer를 제치고 먼저 진입한다. (reader 우선) |