[OS] Operating System(7-1): Synchronization Examples
๐ ์ด์์ฒด์ ์ ๊ณต ์์ ์ ๋ฆฌ
Synchronization ๋ฌธ์ ๋ค์ ์์์ธ bounded-buffer(์ ํ ๋ฒํผ), readers-writers(์ฝ๊ธฐ-์ฐ๊ธฐ), dining philosophers(์์ฌํ๋ ์ฒ ํ์)๋ฌธ์ ์ ๋ํด ์์๋ณด์
Bounded-Buffer Problem
๐Bounded-Buffer Problem: ์ฌ๋ฌ ํ๋ก์ธ์ค๊ฐ ๋ฐ์ดํฐ๋ฅผ ๊ณต์ ๋ฒํผ์ ๋ฃ๊ณ ๋นผ๋ ๊ณผ์ ์์ ๋ฐ์ํ ์ ์๋ ๋๊ธฐํ ๋ฌธ์ (=Producer-Consumer Problem)
- n๊ฐ์ buffer: ๊ฐ ๋ฒํผ๋ ํ ๊ฐ์ ์์ดํ ์ ์ฅ ๊ฐ๋ฅ
- Semaphore:
mutex
: ๊ฐ 1๋ก ์ด๊ธฐํ(์ํธ ๋ฐฐ์ ๋ฅผ ์ํ binary semaphore)full
: ๊ฐ 0์ผ๋ก ์ด๊ธฐํ(์ฑ์์ง ๋ฒํผ ์)empty
: ๊ฐ n์ผ๋ก ์ด๊ธฐํ(๋น์ด์๋ ๋ฒํผ ์)
semaphore์ ๊ฐ = resource ๊ฐ์
- counter ๋ณ์ ์์ด mutex๋ง ์ฌ์ฉํด์ ๋ฌธ์ ๋ฅผ ํด๊ฒฐ ๋ชปํจ!
Counting semaphore์ธ
full
,empty
๋ฅผ ์ฌ์ฉํ๋ ๊ฒ์ด ํจ์จ์ !- producer process ๊ตฌ์กฐ:
1 2 3 4 5 6 7 8 9 10 11 12
while (true) { // ์์ดํ ์์ฐ /* produce an item in next_produced */ wait(empty); // ๋น์ด์๋ ๋ฒํผ๊ฐ ์๋์ง ํ์ธ wait(mutex); // ์๊ณ ์์ญ ์ง์ ์ ์ํ ์ ๊ธ ํ๋ /* add next_produced to the buffer */ signal(mutex); // ์๊ณ ์์ญ ํ์ถ ๋ฐ ์ ๊ธ ํด์ signal(full); // ์ฑ์์ง ๋ฒํผ ์ ์ฆ๊ฐ }
- consumer process ๊ตฌ์กฐ:
1 2 3 4 5 6 7 8 9 10 11
while (true) { wait(full); // ์ฑ์์ง ๋ฒํผ๊ฐ ์๋์ง ํ์ธ wait(mutex); // ์๊ณ ์์ญ ์ง์ ์ ์ํ ์ ๊ธ ํ๋ /* remove an item from buffer to next_consumed */ signal(mutex); // ์๊ณ ์์ญ ํ์ถ ๋ฐ ์ ๊ธ ํด์ signal(empty); // ๋น์ด์๋ ๋ฒํผ ์ ์ฆ๊ฐ /* consume the item in next_consumed */ }
- producer์ consumer๊ฐ ๋ณ๋์ mutex๋ฝ์ ์ฌ์ฉํ๋ ๊ฒ์ด ๋ ํจ์จ์ !
- โ ์์ฐ์์ ์๋น์๊ฐ ๋์์ ์คํ๋ ์ ์๊ธฐ ๋๋ฌธ
Readers-Writers Problem
๐Readers-Writers Problem: ์ฌ๋ฌ ํ๋ก์ธ์ค๊ฐ ๊ณต์ ๋ฐ์ดํฐ์ ์ ๊ทผํ ๋, ์ฝ๊ธฐ ์์ ๊ณผ ์ฐ๊ธฐ ์์ ๊ฐ์ ๋๊ธฐํ๋ฅผ ๊ด๋ฆฌํ๋ ๋ฌธ์
- shared data set: ์ฌ๋ฌ ํ๋ก์ธ์ค๊ฐ ๊ณต์ ํ๋ ๋ฐ์ดํฐ
- Readers: ๋ฐ์ดํฐ๋ฅผ ์ฝ๊ธฐ๋ง ํ๊ณ ์์ X
- Writers: ๋ฐ์ดํฐ๋ฅผ ์ฝ๊ณ ์ธ ์ ์์
โ problem:
- ์ฌ๋ฌ readers๋ ๋์์ ๋ฐ์ดํฐ๋ฅผ ์ฝ์ ์ ์์ด์ผํจ
- writer๋ ๋ ์ ์ ์ผ๋ก ๋ฐ์ดํฐ์ ์ ๊ทผํด์ผ ํจ(ํ ๋ฒ์ ์ค์ง ํ๋์ writer)
- ๋ฐ์ดํฐ ์ผ๊ด์ฑ ์ ์ง + ๋์์ฑ ์ต๋ํ
๐พShared Data:
- Data set: ์ฌ๋ฌ ํ๋ก์ธ์ค๊ฐ ์ ๊ทผํ๋ ๊ณต์ ๋ฐ์ดํฐ
- Semaphore
rw_mutex
: ๊ฐ์ด 1๋ก ์ด๊ธฐํ๋ ์ธ๋งํฌ์ด, reader์ writer์ ์ํธ๋ฐฐํ ์ ๊ทผ์ ๊ด๋ฆฌ - Semaphore
mutex
: ๊ฐ์ด 1๋ก ์ด๊ธฐํ๋ ์ธ๋งํฌ์ด, reader๊ฐ read_count๋ฅผ ์ ๋ฐ์ดํธํ๊ธฐ ์ํด ์ฌ์ฉ Integer
read_count
: 0์ผ๋ก ์ด๊ธฐํ๋ ๋ณ์, ํ์ฌ ์งํ ์ค์ธ reader์ ์- Writer Process:
1 2 3 4 5 6 7
while (true) { wait(rw_mutex); // ๋ ์ ์ ์ ๊ทผ ๊ถํ ํ๋ /* writing is performed */ signal(rw_mutex); // ์ ๊ทผ ๊ถํ ํด์ }
- ์ค์ง ํ ๊ฐ์ writer๋ง ๋ค์ด๊ฐ ์ ์์ด์ผ ํจ
- ์ด ํด๋ multiple reader๋ฅผ ํ์ฉํ์ง๋ง writer๊ฐ ์ง์์ ์ผ๋ก ๊ตถ์ ์ ์๋ค.
โ โreader ์ ํธโ ์๊ณ ๋ฆฌ์ฆ
- Reader Process:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22
while (true) { wait(mutex); // read_count ์ ๋ฐ์ดํธ ๋ณดํธ๋ฅผ ์ํ ์ ๊ธ ํ๋ read_count++; // ์ฝ๊ธฐ ํ๋ก์ธ์ค ์ ์ฆ๊ฐ // ์ ์ผํ reader๋ผ๋ฉด writer์ ๊ฒฝ์, ๊ทธ๋ ์ง ์๋ค๋ฉด ๋ค๋ฅธ reader๊ฐ ๋ค์ด์ค๋ ๊ฒ์ ํ์ฉ if (read_count == 1) { wait(rw_mutex); // ์ฒซ ๋ฒ์งธ reader๊ฐ writer ์ ๊ทผ ์ฐจ๋จ } signal(mutex); // read_count ์ ๋ฐ์ดํธ ์๋ฃ, ์ ๊ธ ํด์ /* reading is performed */ //โ reader๊ฐ ์ค๋ณตํด์ ๋ค์ด์ค๋ ๊ฒ์ ํ์ฉ wait(mutex); // read_count ์ ๋ฐ์ดํธ ๋ณดํธ๋ฅผ ์ํ ์ ๊ธ ์ฌํ๋ read_count--; // ์ฝ๊ธฐ ํ๋ก์ธ์ค ์ ๊ฐ์ if (read_count == 0) { // ๋ ์ด์ reader๊ฐ ์์ผ๋ฏ๋ก writer ํ์ฉ signal(rw_mutex); // ๋ง์ง๋ง reader๊ฐ writer ์ ๊ทผ ํ์ฉ } signal(mutex); // read_count ์ ๋ฐ์ดํธ ์๋ฃ, ์ ๊ธ ํด์ }
- ์ฒซ ๋ฒ์งธ reader๊ฐ ๋ค์ด์ฌ ๋๋ง
rw_mutex
๋ฅผ ํ๋ โ writer์ ์ ๊ทผ์ ์ฐจ๋จ - ๋ง์ง๋ง reader๊ฐ ๋๊ฐ ๋๋ง
rw_mutex
๋ฅผ ํด์ โ ๋ชจ๋ reader๊ฐ ์์ ์ ์๋ฃํ๋ฉด writer๊ฐ ์ ๊ทผ ๊ฐ๋ฅ
Readers-Writers Problem Variations
์ฝ๊ธฐ-์ฐ๊ธฐ ๋ฌธ์ ์๋ ์ฌ๋ฌ ๋ณํ์ด ์กด์ฌ, ๋ชจ๋ ์ด๋ค ํํ์ ์ฐ์ ์์๋ฅผ ํฌํจ
1. First variation - Reader Priority
- reader๋ ๋๊ธฐํ์ง ์๊ณ ๋ฐ๋ก ์คํ๋จ
- writer๋ ๋ชจ๋ reader๊ฐ ์๋ฃ๋ ๋๊น์ง ๋๊ธฐ
- โ writer์ starvation ๊ฐ๋ฅ์ฑ ์์!
2. second variation - Writer Priority
- writer๊ฐ ๋๊ธฐ ์ค์ด๋ฉด ์๋ก์ด reader๋ ์์ํ ์ ์์
- reader์** ์ค๋ณต์ ์ต๋ํ ํ์ฉํ์ง๋ง ๊ธฐ๋ค๋ฆฌ๋ writer๊ฐ ์์ผ๋ฉด **reader๋ writer๋ฅผ ์์ง๋ฅด์ง ๋ชปํจ
- ๋ฆ๊ฒ ์จ writer๋ ๊ธฐ๋ค๋ฆฌ๊ณ ์๋ reader๋ฅผ ์์ง๋ฅผ ์ ์๋ค
- writer๊ฐ ๊ฐ๋ฅํ ๋นจ๋ฆฌ ์คํ๋จ
- reader์ starvation ๊ฐ๋ฅ์ฑ ์์!
๋ ๋ณํ ๋ชจ๋ starvation์ ๊ฐ๋ฅ์ฑ์ด ์์ผ๋ฉฐ, ์ด๋ก ์ธํด ๋ ๋ง์ ๋ณํ์ด ์๊น
Fair Solution
- ๊ณต์ ํ reader-writer: ์ ์ฐฉ์์ผ๋ก CS์ ๋ค์ด๊ฐ๋ฉด์ reader์ ์ค๋ณต์ ์ต๋ํ ํ์ฉํ๋ ๋ฐฉ์
- ๋ฆ๊ฒ ์จ reader/writer๊ฐ ๊ธฐ๋ค๋ฆฌ๊ณ ์๋ ๋ค๋ฅธ reader/writer๋ฅผ ์์ง๋ฅด์ง ๋ชปํจ!
- ํ๋ก์ธ์ค์ ๋์ฐฉ ์์(FIFO)์ ๋ฐ๋ผ ์ ๊ทผ ๊ถํ ๋ถ์ฌ
- ๊ฐ๋ฅํ ํ ๋ง์ ์ฝ๊ธฐ ํ๋ก์ธ์ค ๋์ ์ ๊ทผ ํ์ฉ
- ๋ฆ๊ฒ ๋์ฐฉํ ํ๋ก์ธ์ค๋ ๋จผ์ ๋๊ธฐ ์ค์ธ ํ๋ก์ธ์ค๋ฅผ ์ถ์ํ ์ ์์
Dining Philosophers Problem
๐Dining Philosophers Problem: ๊ต์ฐฉ ์ํ(deadlock)์ ๊ธฐ์ ์ํ(starvation)๋ฅผ ์ค๋ช
ํ๊ธฐ ์ํ ์ ๋ช
ํ ์์
- 5๋ช ์ ์ฒ ํ์๊ฐ ์ํ ํ ์ด๋ธ์ ์์ ์๋ค.
- ๊ฐ ์ฒ ํ์ ์ฌ์ด์๋ ํ๋์ ์ ๊ฐ๋ฝ(chopstick)์ด ์์ด ์ด 5๊ฐ์ ์ ๊ฐ๋ฝ์ด ์๋ค.
- ์ฒ ํ์๋ค์ ์๊ฐํ๊ธฐ(
thinking
)์ ๋จน๊ธฐ(eating
)๋ฅผ ๋ฒ๊ฐ์ ์ํ - ์ฒ ํ์๊ฐ ์์ฌ๋ฅผ ํ๋ ค๋ฉด ์ข์ฐ ์์ชฝ์ ์ ๊ฐ๋ฝ 2๊ฐ๋ฅผ ๋ชจ๋ ์ง์ด์ผ ํ๋ค.
- ์ ๊ฐ๋ฝ์ ํ ๋ฒ์ ํ๋์ฉ ์ง์ ์ ์์ผ๋ฉฐ, ์์ฌ๊ฐ ๋๋๋ฉด ๋ ์ ๊ฐ๋ฝ์ ๋ชจ๋ ๋ด๋ ค๋๋๋ค.
Shared Data:
- Bowl of rice: ๊ณต์ data set
chopstick [5]
: ๊ฐ๊ฐ 1๋ก ์ด๊ธฐํ๋ semaphore ๋ฐฐ์ด
์ธ๋งํฌ์ด๋ฅผ ํ์ฉํ ๊ธฐ๋ณธ์ ์ธ solution
์ ์๊ณ ๋ฆฌ์ฆ์ deadlock ๊ฐ๋ฅ์ฑ์ด ์๋ค!
- ๋ชจ๋ ์ฒ ํ์๊ฐ ๋์์ ์ผ์ชฝ ์ ๊ฐ๋ฝ์ ์ก์
- ์ค๋ฅธ์ชฝ ์ ๊ฐ๋ฝ์ ์ด๋ฏธ ๋ค๋ฅธ ์ฒ ํ์๊ฐ ์ก๊ณ ์์ด์ ๋๊ธฐ
- ๋ชจ๋ ์ฒ ํ์๊ฐ ๋ฌดํ ๋๊ธฐ ์ํ๊ฐ ๋จ
โ deadlock์ ํผํ๋ ๋ฐฉ๋ฒ:
- ์ ๊ฐ๋ฝ ๋ ๊ฐ๋ฅผ ๋ค ์ง์ ์ ์์ ๋๋ง ์ง๋๋ค.
- atomic ์ฐ์ฐ์ผ๋ก ๋ ์ ๊ฐ๋ฝ์ ๋ชจ๋ ์ง๊ฑฐ๋ ์์ ์ง์ง ์์
- ์ค๋ฆ์ฐจ์์ผ๋ก ์ง๋๋ค.
- ์ง์๋ฒ ์ฒ ํ์๋ ์ผ์ชฝโ์ค๋ฅธ์ชฝ, ํ์๋ฒ ์ฒ ํ์๋ ์ค๋ฅธ์ชฝโ์ผ์ชฝ ์์ผ๋ก ์ง๋๋ค.
circular wait
์กฐ๊ฑด์ ๊นจ๋จ๋ฆผ
- ํ
์ด๋ธ์ ์ต๋ 4๋ช
๋ง ์๋๋ค.
- ์ต๋ 4๋ช ๋ง ํ ์ด๋ธ์ ๋์์ ์์ ์ ์๋๋ก ๊ตฌํ โ ์ต์ ํ ๋ช ์ ๋ฌด์กฐ๊ฑด ์ ๊ฐ๋ฝ ๋ ๊ฐ ๊ฐ๋ฅ
Monitor๋ฅผ ์ด์ฉํ solution
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
monitor DiningPhilosophers {
enum { THINKING, HUNGRY, EATING } state[5];
condition self[5];
void pickup(int i) {
state[i] = HUNGRY;
test(i);
if (state[i] != EATING) self[i].wait;
}
void putdown(int i) {
state[i] = THINKING;
// test left and right neighbors
test((i + 4) % 5);
test((i + 1) % 5);
}
void test(int i) {
if ((state[(i + 4) % 5] != EATING) &&
(state[i] == HUNGRY) &&
(state[(i + 1) % 5] != EATING)) {
state[i] = EATING;
self[i].signal();
}
}
// ์ด๊ธฐํ ์ฝ๋
initialization_code() {
for (int i = 0; i < 5; i++)
state[i] = THINKING; // ๋ชจ๋ ์ฒ ํ์์ ์ด๊ธฐ ์ํ๋ ์๊ฐํ๊ธฐ
}
}
- ์ฒ ํ์์ ์ํ ๊ด๋ฆฌ:
1
enum { THINKING, HUNGRY, EATING } state[5];
- THINKING: ์ฒ ํ์๊ฐ ์๊ฐํ๋ ์ํ
- HUNGRY: ์ฒ ํ์๊ฐ ๋ฐฐ๊ณ ํ์ ์ ๊ฐ๋ฝ์ ์ง์ผ๋ ค๋ ์ํ
- EATING: ์ฒ ํ์๊ฐ ์์ฌ ์ค์ธ ์ํ
- ์กฐ๊ฑด ๋ณ์:
1
condition self[5];
- ๋ฐฐ๊ณ ํ์ง๋ง ์ ๊ฐ๋ฝ์ ์ง์ ์ ์์ ๋ ๊ธฐ๋ค๋ฆฌ๊ธฐ ์ํด ์ฌ์ฉํ๋ ์กฐ๊ฑด ๋ณ์
- ํฝ์
ํจ์:
1 2 3 4 5
void pickup(int i) { state[i] = HUNGRY; // ์ํ๋ฅผ ๋ฐฐ๊ณ ํ์ผ๋ก ๋ณ๊ฒฝ test(i); // ์ ๊ฐ๋ฝ์ ์ง์ ์ ์๋์ง ํ์ธ if (state[i] != EATING) self[i].wait; // ์์ฌํ ์ ์์ผ๋ฉด ๋๊ธฐ }
- ๋ด๋ ค๋๊ธฐ ํจ์:
1 2 3 4 5 6
void putdown(int i) { state[i] = THINKING; // ์ํ๋ฅผ ์๊ฐํ๊ธฐ๋ก ๋ณ๊ฒฝ // ์ข์ฐ ์ด์ ํ์ธ test((i + 4) % 5); // ์ผ์ชฝ ์ด์ ํ์ธ test((i + 1) % 5); // ์ค๋ฅธ์ชฝ ์ด์ ํ์ธ }
test ~
: ์ข์ฐ์ ๋๊ฐ ๋จน๊ธฐ๋ฅผ ๊ธฐ๋ค๋ฆฌ๊ณ ์์ผ๋ฉด ๊นจ์์ค
- test ํจ์:
1 2 3 4 5 6 7 8
void test(int i) { if ((state[(i + 4) % 5] != EATING) && // ์ผ์ชฝ ์ด์์ด ์์ฌ ์ค์ด ์๋๊ณ (state[i] == HUNGRY) && // ์์ ์ด ๋ฐฐ๊ณ ํ๊ณ (state[(i + 1) % 5] != EATING)) { // ์ค๋ฅธ์ชฝ ์ด์์ด ์์ฌ ์ค์ด ์๋๋ฉด state[i] = EATING; // ์ํ๋ฅผ ์์ฌ ์ค์ผ๋ก ๋ณ๊ฒฝ self[i].signal(); // ๋๊ธฐ ์ค์ด๋ ์ฒ ํ์ ๊นจ์ฐ๊ธฐ } }
์ฒ ํ์ ํ๋ก์ธ์ค๋ ๋ชจ๋ํฐ์ ํจ์๋ฅผ ํธ์ถํ์ฌ ์คํ๋จ:
1
2
3
4
5
DiningPhilosophers.pickup(i); // ์ ๊ฐ๋ฝ ์ง๊ธฐ ์๋
/** EAT **/ // ์์ฌ
DiningPhilosophers.putdown(i); // ์ ๊ฐ๋ฝ ๋ด๋ ค๋๊ธฐ
- No deadlock, but starvation is possible
- ํน์ ์ฒ ํ์๊ฐ ๊ณ์ํด์ ์์ฌ ๊ธฐํ๋ฅผ ์ป์ง ๋ชปํ ์ ์๋ค
๊ฐ problem ์ ๋ฆฌ
bounded-buffer: ์ธ๋งํฌ์ด ์ฌ์ฉ(
mutex
,empty
,full
). ์นด์ดํ ์ธ๋งํฌ์ด๋ก ๋ฒํผ ์ํ ์ถ์ . ์์ฐ์์ ์๋น์ ๊ฐ ๋๊ธฐํreader-writer: ์ธ๋งํฌ์ด์ ์นด์ดํฐ(
mutex
,rw_mutex
,read_count
) ์ฌ์ฉ. ์ฝ๊ธฐ ํ๋ก์ธ์ค ๋์ ์ ๊ทผ ํ์ฉ, ์ฐ๊ธฐ ํ๋ก์ธ์ค ๋ ์ ์ ๊ทผ ๋ณด์ฅdining philosophers: ์ธ๋งํฌ์ด(chopstick[5]) ๋๋ ๋ชจ๋ํฐ ์ฌ์ฉ. ๋ชจ๋ํฐ๋ ์กฐ๊ฑด ๋ณ์์ ์ํ ๊ด๋ฆฌ๋ฅผ ํตํด ๊ต์ฐฉ ์ํ ๋ฐฉ์ง