๋ณธ ๊ฒ์๊ธ์ KOCW ์ดํ์ฌ์๋ํ๊ต ๋ฐํจ๊ฒฝ ๊ต์๋์ <์ด์์ฒด์ > ๊ฐ์๋ฅผ ๋ฃ๊ณ ,
<ํผ์ ๊ณต๋ถํ๋ ์ปดํจํฐ๊ตฌ์กฐ + ์ด์์ฒด์ > ์ฑ ์ ์ฐธ๊ณ ํ์ฌ ์ ๋ฆฌํ ๋ด์ฉ์ ๋๋ค.
๊ฒ์๊ธ์ ํฌํจ๋๋ ์ด๋ฏธ์ง ์๋ฃ๋ <์ด์์ฒด์ > ๊ฐ์์ ํฌํจ๋ ๊ฐ์ ์๋ฃ์ ๋๋ค.
Synchronization๊ณผ ๊ด๋ จ๋ ๊ณ ์ ์ ์ธ ๋ฌธ์
- Bounded-Buffer Problem (Producer-Consumer Problem)
- Readers and Writers Problem
- Dining-Philosophers Problem
1. Bounded-Buffer Problem(Producer-Consumer Problem)
์๋๋ฆฌ์ค
๋ ์ข ๋ฅ์ ํ๋ก์ธ์ค ์กด์ฌ
1. ์์ฐ์(producer) ํ๋ก์ธ์ค: ๋ฐ์ดํฐ ์์ฐํด์ ๊ณต์ ๋ฒํผ์ ๋ฃ์
2. ์๋น์(consumer) ํ๋ก์ธ์ค: ๋ฐ์ดํฐ๋ฅผ ๋ฒํผ์์ ๊บผ๋ด๊ฐ์ ์๋น
๋ฐ์ ๊ฐ๋ฅํ ๋ฌธ์
1. lock๊ณผ ๊ด๋ จ๋ ๋ฌธ์
์์ฐ์, ์๋น์ ํ๋ก์ธ์ค๊ฐ ๊ณต์ ๋ฒํผ์ ๋ฐ์ดํฐ์ ๋์์ ์ ๊ทผํ ์ ์๋ค. - ๋ฒํผ์ ๋ํ lock์ด ํ์
2. ๋ฒํผ๊ฐ ์ ํํ๊ธฐ ๋๋ฌธ์ ์๊ธฐ๋ ๋ฌธ์
์์ฐ์ ์ ์ฅ์์๋ ๋น์ด์๋ ๋ฒํผ๊ฐ ์์์ด๊ธฐ ๋๋ฌธ์ ๋ฒํผ๊ฐ ๋ค ์ฐผ๋ค๋ฉด empty ๋ฒํผ๊ฐ ์๊ธธ ๋๊น์ง ๊ธฐ๋ค๋ ค์ผ ํจ
์๋น์ ์ ์ฅ์์๋ ๋ฐ์ดํฐ๊ฐ ๋ค์ด์๋ ๋ฒํผ๊ฐ ์์์ด๊ธฐ ๋๋ฌธ์ empty ๋ฒํผ ๋ฟ์ด๋ผ๋ฉด ์์ฐ์๊ฐ ๋ฐ์ดํฐ๋ฅผ ์์ฐํด ๋ฒํผ์ ๋ฃ์ด์ค ๋๊น์ง ๊ธฐ๋ค๋ ค์ผ ํจ
์์ฐ์-์๋น์ ๋ฌธ์ ์์ ํ์ํ ์ธ๋งํฌ์ด์ ์ญํ
1. ๊ณต์ ๋ฐ์ดํฐ(shared data)์ ์ํธ๋ฐฐ์ (lock ๊ฑธ๊ณ ํธ๋ ์์ )๋ฅผ ์ํ ์ธ๋งํฌ์ด
2. ๊ฐ์ฉ ๋ฒํผ๋ฅผ ์นด์ดํธํด์ฃผ๋ ์ธ๋งํฌ์ด
Synchronization variables
semaphore full = 0, empty = n, mutex = 1;
/*
full: ๋ฐ์ดํฐ ๋ค์ด์๋ ๋ฒํผ ๊ฐ์
empty: ๋น์ด์๋ ๋ฒํผ ๊ฐ์
mutex: ๊ณต์ ๋ฒํผ์ ํ๋์ ํ๋ก์ธ์ค๋ง ์ ๊ทผํ๊ฒ ํ๊ธฐ ์ํ ๋ณ์ (lock)
*/
Producer
do {
produce an item in x
P(empty); // ๋น ๋ฒํผ๊ฐ ์๋ค๋ฉด ํ๋ ํ๋ (empty 1 ๊ฐ์)
P(mutex); // ๋ฒํผ์ ์ ๊ทผํด ๋ฐ์ดํฐ๋ฅผ ์ง์ด๋ฃ๊ธฐ ์ํด lock
add x to buffer
V(mutex); // ๋ฐ์ดํฐ ์ฝ์
์์
๋๋๋ฉด unlock
V(full); // full 1์ฆ๊ฐ(์๋น์ ๊นจ์์ค ์ ์๋๋ก)
} while(1)
Consumer
do {
P(full); // full ๋ฒํผ ์๋ค๋ฉด ํ๋ ํ๋ (full 1 ๊ฐ์)
P(mutex); // ํ๋ํ๋ค๋ฉด ๋ฒํผ ์ ์ฒด์ lock
remove an item from buffer to y
V(mutex); // unlock
V(empty); // empty 1์ฆ๊ฐ
comsume the item in y
} while(1);
2. Readers-Writers Problem
์๋๋ฆฌ์ค
๊ณต์ ์์์ ๋ฐ์ดํฐ๋ฅผ ์ฝ๊ธฐ๋ง ํ๋ reader ์ ๋ฐ์ดํฐ๋ฅผ ๋ณ๊ฒฝํ ์ ์๋ writer ์กด์ฌ
- reader: ๊ณต์ ๋ฐ์ดํฐ์ ๋์์ ์ฌ๋ฌ ํ๋ก์ธ์ค๊ฐ ์ ๊ทผํด๋ ๋จ (๋ฌธ์ x)
- writer: ํ๋์ ํ๋ก์ธ์ค๊ฐ ๋ฐ์ดํฐ์ ์ ๊ทผ ์ค์ด๋ฉด ๋ค๋ฅธ ํ๋ก์ธ์ค๋ค์ ์ ๊ทผ ๊ธ์ง๋จ
Shared data
int readcount = 0; // ํ์ฌ DB์ ์ ๊ทผ ์ค์ธ reader์ ์
DB; // ๊ณต์ ๋ฐ์ดํฐ
Synchronization variables
semaphore mutex = 1, db = 1;
/*
mutex: readcount๋ฅผ ์ํ lock
db: DB์ ๋ํ lock
*/
Writer
P(db); // lock
writing DB is performed;
V(db); // unlock
Reader
P (mutex); // readcount ์ ๋ํ lock (writer๊ฐ ์ ๊ทผํ๋ฉด ๋ฐ์ดํฐ๊ฐ ๋ณ๊ฒฝ๋๋ฏ๋ก)
readcount++;
if (readcount == 1) P(db); // ์ฒ์์ผ๋ก ์ ๊ทผํ๋ reader ๋ผ๋ฉด db์ lock
V(mutex); // unlock
reading DB is performed
P(mutex);
readcount--;
if (readcount == 0) V(db); // reader ๊ฐ ์๋ค๋ฉด, writer๋ ๊ธฐ๋ค๋ ธ๋ค๊ฐ ์ ๊ทผ ๊ฐ๋ฅ
V(mutex); // unlock
reader๊ฐ DB์ ์ ๊ทผํด์ ์ฝ๋ ์์ ์ ์ํํ๊ณ ์๋ ๋์ค์ writer๊ฐ ์ ๊ทผํ๋ ค๊ณ ํ๋ค๋ฉด writer๋ reader์ ์์ ์ด ๋๋๊ณ lock์ด ํ๋ฆด ๋๊น์ง ๊ธฐ๋ค๋ ค์ผ ํฉ๋๋ค. ๊ธฐ๋ค๋ฆฌ๋ ์ค์ reader๊ฐ ๊ณ์ ๋ค์ด์จ๋ค๋ฉด writer๋ ๋ชจ๋ reader๊ฐ ๋๊ฐ๋๊น์ง ๊ณ์ ๊ธฐ๋ค๋ ค์ผ ํ๊ธฐ ๋๋ฌธ์ starvation ๋ฌธ์ ๊ฐ ๋ฐ์ํ ์ ์์ต๋๋ค.
3. Dining-Philosophers Problem
์๋๋ฆฌ์ค
5๋ช
์ ์ฒ ํ์๊ฐ ์ํ์ ๋๋ฌ์์์ ๋ฐฅ์ ๋จน๋๋ฐ ์ ๊ฐ๋ฝ์ด ์ฒ ํ์ ์ ์์ผ๋ก 1๊ฐ์ฉ ์ด 5๊ฐ ๋์ฌ์์ต๋๋ค.
์ฒ ํ์๋ ์๊ฐ์ ํ๊ฑฐ๋ ์์ฌ๋ฅผ ํ ์ ์๋๋ฐ, ์ ๊ฐ๋ฝ ์์ชฝ์ ๋ชจ๋ ์ง์ด์ผ ์์ฌ๋ฅผ ํ ์ ์์ต๋๋ค.
Synchronization variables
Semaphore chopstick[5] = { 1 }; // ์ ์ ์ฒ ํ์๊ฐ ๊ณต์ ํ๋ ์์์ธ ์ ๊ฐ๋ฝ
Philosopher i
do {
P(chopstick[i]);
P(chopstick[(i + 1) % 5];
eat();
V(chopstick[i]);
V(chopstick[(i + 1) % 5];
think();
} while(1);
์ ์ฝ๋์ ๋ฌธ์ ์
- Deadlock์ ๊ฐ๋ฅ์ฑ
- ๋ชจ๋ ์ฒ ํ์๊ฐ ๋์์ ์ผ์ชฝ ์ ๊ฐ๋ฝ์ ์ง์ด๋ฒ๋ฆฐ ๊ฒฝ์ฐ ์๋ฌด๋ ์์ฌ๋ฅผ ํ์ง ๋ชปํ๊ณ ์ค๋ฅธ์ชฝ ์ ๊ฐ๋ฝ์ ๊ณ์ ๊ธฐ๋ค๋ฆผ
ํด๊ฒฐ ๋ฐฉ์
- 4๋ช ์ ์ฒ ํ์๋ง์ด ํ ์ด๋ธ์ ๋์์ ์์ ์ ์๋๋ก ํ๋ค. (์ธ์ ์ ์ค์ด๊ธฐ)
- ์ ๊ฐ๋ฝ์ ๋ ๊ฐ ๋ชจ๋ ์ง์ ์ ์์ ๋์๋ง ์ ๊ฐ๋ฝ์ ์ง์ ์ ์๊ฒ ํ๋ค.
- ๋น๋์นญ: ์ง์(ํ์) ์ฒ ํ์๋ ์ผ์ชฝ(์ค๋ฅธ์ชฝ) ์ ๊ฐ๋ฝ๋ถํฐ ์ง๋๋ก ํ๋ค. (์ ๊ฐ๋ฝ์ ์ฐ์ ์์๋ฅผ ๋๊ธฐ)
enum { thinking, hungry, eating } state[5]; // ์ฒ ํ์์ ์ํ
semaphore self[5] = 0; // ์์ชฝ ์ ๊ฐ๋ฝ์ ์ก์ ๊ถํ. ์ฒ์์ ์ ๋ถ ๊ถํ์ด ์์(0)
semaphore mutex = 1; // lock - ์ ์ฒ ํ์์ ์ํ๊ฐ ๋ฐ๋๋ฉด ๋์ ์ ๊ฐ๋ฝ์ ์ง์ ๊ถํ์๋ ์ํฅ์ด ์ค๊ธฐ ๋๋ฌธ์ ์ํ๋ฅผ ๋ฐ๊พธ๊ธฐ ์ ์ lock ์ ๊ฑธ์ด์ผ
do {
pickup(i);
eat();
putdown(i);
think();
} while(1);
void pickup(int i) {
P(mutex); // lock for state
state[i] = hungry;
test(i); // ์ ๊ฐ๋ฝ ์ก์ ์ ์๋ ๊ถํ์ ๋ํ ์กฐ๊ฑด ์ฒดํฌ
V(mutex); // unlock
P(self[i]); // self[i] 1 -> 0 ๋ง์ฝ ์ ๊ฐ๋ฝ์ ์ก์ ์ ์๋ค๋ฉด ์ ๊ฐ๋ฝ ์ฌ์ฉ, ์๋ค๋ฉด ๋๊ธฐ.
}
void putdown(int i) {
P(mutex); // lock for state
state[i] = thinking;
// ์ ์ ์ฒ ํ์๊ฐ ๋ด๊ฐ ์ ๊ฐ๋ฝ์ ์ฅ๊ณ ์์ด์ ๋ฐฅ์ ๋ชป๋จน์๋ค๋ฉด ๋จน์ ์ ์๊ฒ ํด์ค
test((i + 1) % 5); // ์ค๋ฅธ์ชฝ
test((i - 1) % 5); // ์ผ์ชฝ
V(mutex); // unlock
}
void test(int i) {
// ์กฐ๊ฑด: ์ ์ชฝ์ด ์์ฌ์ค์ด ์๋๋ฉด์ ๋์ state๋ hungry
if (state[(i - 1) % 5] != eating && state[i] == hungry && state[(i + 1) % 5] != eating) {
state[i] = eating;
V(self[i]); // self[i] 0 -> 1 ์ ๊ฐ๋ฝ์ ์ก์ ๊ถํ ๋ถ์ฌ
}
}
์์ ์ฝ๋๋ก ๋ณด๋ ์ธ๋งํฌ์ด์ ๋ฌธ์ ์
- ์ฝ๋ฉํ๊ธฐ ํ๋ค๋ค
- ์ ํ์ฑ์ ์ ์ฆ์ด ์ด๋ ต๋ค
- ์ธํฐํ์ด์ค ์์ด ์๋ฐ์ ํ๋ ฅ์ด ํ์ํ๋ค
- ํ๋ฒ์ ์ค์๊ฐ ๋ชจ๋ ์์คํ ์ ์น๋ช ์ ์ํฅ
P(mutex)
critical section
V(mutex)
// ๋ง์ฝ ์ค์๋ก ์ฝ๋ ์๋ชป ์ด๋ค๋ฉด1 - Mutual exclusion ๊นจ์ง
V(mutex)
critical section
P(mutex)
// ๋ง์ฝ ์ค์๋ก ์ฝ๋ ์๋ชป ์ด๋ค๋ฉด - Deadlock
P(mutex)
critical section
P(mutex)
ํด๊ฒฐ์ฑ 3: Monitor
ํ๋ก๊ทธ๋๋ฐ ์ธ์ด์ฐจ์์์ ํ๋ก์ธ์ค ๋๊ธฐํ ๋ฌธ์ ๋ฅผ ํด๊ฒฐํ๋ ๋ฐฉ๋ฒ์ผ๋ก, ๋์ ์ํ์ค์ธ ํ๋ก์ธ์ค ์ฌ์ด์์ ์ถ์์๋ฃํ์ ์์ ํ๊ฒ ๊ณต์ ํ ์ ์๊ฒ ๋ณด์ฅํด์ฃผ๋ high-level synchronization construct ์ ๋๋ค.
- ๊ณต์ ์์์ ๋์ ์ ๊ทผ์ ๋ง๋ ๊ฒ์ ๋ชจ๋ํฐ ์ฐจ์์์ ์ง์ (ํ๋ก๊ทธ๋๋จธ ์ ์ฅ์์ ํจ์ฌ ์์ํ ๋ฐฉ๋ฒ)
- ๊ณต์ ์์๊ณผ ๊ณต์ ์์์ ์ ๊ทผํ๊ธฐ ์ํ ์ธํฐํ์ด์ค(ํต๋ก)๋ฅผ ๋ฌถ์ด ๊ด๋ฆฌ
- ํ๋ก์ธ์ค๋ ๋ฐ๋์ ์ธํฐํ์ด์ค๋ฅผ ํตํด์๋ง ๊ณต์ ์์์ ์ ๊ทผํ ์ ์๋๋ก ํจ
- ๋ชจ๋ํฐ ์์ ํญ์ ํ๋์ ํ๋ก์ธ์ค๋ง ๋ค์ด์ค๋๋ก ํ์ฌ ์ํธ ๋ฐฐ์ ๋ฅผ ์ํ ๋๊ธฐํ๋ฅผ ์ ๊ณต
- ๊ณต์ ์์์ ๋ค๋ฃจ๋ ์ธํฐํ์ด์ค์ ์ ๊ทผํ๊ธฐ ์ํ ํ(= ๋ชจ๋ํฐ์ ์ง์ ํ๊ธฐ ์ํ ํ)๋ฅผ ๋ง๋ค๊ณ , ๋ชจ๋ํฐ ์์ ํ๋ก์ธ์ค๊ฐ ์๋ค๋ฉด ํ์ ์ฝ์ ํด ์ค์ ์ธ์
- ๋ชจ๋ํฐ ์์ ์๋ activeํ ํ๋ก์ธ์ค์ ์๊ฐ 0์ด ๋ ๋ ํ์ ํ๋ก์ธ์ค๋ค์ด ์ ๊ทผํ ์ ์๊ฒ ๋จ
๋ชจ๋ํฐ์ ์คํ ์์ ์ ์ด๋ฅผ ์ํ ๋๊ธฐํ ๋ฐฉ๋ฒ
๋ชจ๋ํฐ ๋ด์์๋ ํ๋ฒ์ ํ๋์ ํ๋ก์ธ์ค๋ง์ด ํ๋ ๊ฐ๋ฅํฉ๋๋ค. ์ด๋ฅผ ์ ์ดํ๊ธฐ ์ํด ํ๋ก๊ทธ๋๋จธ๊ฐ ๋๊ธฐํ ์ ์ฝ ์กฐ๊ฑด์ ๋ช ์์ ์ผ๋ก ์ฝ๋ฉํ ํ์๊ฐ ์์ผ๋ฉฐ, ํ๋ก์ธ์ค๊ฐ ๋ชจ๋ํฐ ์์์ ๊ธฐ๋ค๋ฆด ์ ์๋๋ก ํ๊ธฐ ์ํด condition variable(์กฐ๊ฑด ๋ณ์)์ ์ฌ์ฉํฉ๋๋ค.
condition variable
- ๊ฐ์ ๊ฐ์ง๋ ๋ณ์๊ฐ ์๋๋ฉฐ, ์ด๋ค ํ๋ก์ธ์ค๋ฅผ ์ ๋ค๊ฒ ํ๊ณ ์ค ์ธ์ฐ๊ธฐ ์ํ ๋ณ์
- wait, signal ์ฐ์ฐ์ ์ํด ์ ๊ทผ ๊ฐ๋ฅ
- wait: ๊ณต์ ์์์ ์ฌ๋ถ์ด ์์ ๋ signal ํธ์ถ ์ ๊น์ง ํ๋ก์ธ์ค ์ ๋ค๊ฒ ํจ
- signal: ํ๋ก์ธ์ค๋ฅผ ๊นจ์ฐ๋ ์ญํ . ์ด์ ์ ๊ณต์ ์์์ ์ ๊ทผํ ํ๋ก์ธ์ค๊ฐ ๋๊ฐ๋ฉด์ ํธ์ถํจ. suspended ๊ฐ ์์ผ๋ฉด ์๋ฌด ์ผ๋ ์ผ์ด๋์ง ์์.
์ฝ๋ ๊ตฌํ ์์
Bounded-Buffer
๊ณต์ ๋ฒํผ๊ฐ ๋ชจ๋ํฐ ๋ด๋ถ์ ์์ผ๋ฉด์, ์์ฐ์ or ์๋น์ ํ๋ก์ธ์ค๊ฐ ์ ๊ทผํ๋ ค๊ณ ํ ๋ monitor ๋ด๋ถ ์ฝ๋๋ฅผ ์คํํด์ผ ํ๊ธฐ ๋๋ฌธ์ ํ๋ฒ์ ํ๋์ ํ๋ก์ธ์ค๋ง ํ์ฑํ๋ฉ๋๋ค. (lock/unlock ํ์x)
monitor bounded_buffer {
int buffer[N];
condition full, empty;
/*
๊ฐ์ ๊ฐ์ง์ง ์๊ณ , ์์ ์ ํ์ ํ๋ก์ธ์ค๋ฅผ ๋งค๋ฌ์์ sleep ์ํค๊ฑฐ๋ ํ์์ ํ๋ก์ธ์ค๋ฅผ ๊นจ์์ฃผ๋ ์ญํ ๋ง ํจ
full: ๋ฐ์ดํฐ๊ฐ ์๋ ๋ฒํผ๋ฅผ ๊ธฐ๋ค๋ฆฌ๋ ํ๋ก์ธ์ค๋ฅผ ์ค์ธ์
empty: ๋ฐ์ดํฐ๊ฐ ์๋ ๋ฒํผ๋ฅผ ๊ธฐ๋ค๋ฆฌ๋ ํ๋ก์ธ์ค๋ฅผ ์ค์ธ์
*/
void produce(int x) {
if there is no empty buffer
empty.wait(); // ์์ฐ์ ๊ธฐ์ค ์์ ์์ -> ์ ๋ค๋๋ก
add x to an empty buffer
full.signal(); // ์๋น์ ๊นจ์
}
void consume(int x) {
if there is no full buffer
full.wait(); // ์๋น์ ๊ธฐ์ค ์์ ์์ -> ์ ๋ค๋๋ก
add x to an full buffer
empty.signal(); // ์์ฐ์ ๊นจ์
}
}
Dining Philosophers
์ฝ๋ ๊ตฌํ์ ์ธ๋งํฌ์ด์ ๋น์ทํ์ง๋ง ์ฐจ์ด์ ์ lock/unlock ์์ ์ด ์๋ค๋ ์ ์ ๋๋ค. (๋์ if๋ฌธ์ผ๋ก ์ํ์ฒดํฌ ํ ํ๋ก์ธ์ค ์ ๋ค๋๋ก)
monitor dining_philosopher {
enum { thinking, hungry, eating } state[5];
condition self[5];
void pickup(int i) {
state[i] = hungry;
test(i); // ์ ๊ฐ๋ฝ 2๊ฐ๋ฅผ ๋ค ์ก์ ์ ์๋์ง์ ๋ํ ๊ถํ ์ฒดํฌ
if (state[i] != eating)
self[i].wait(); // cf) semaphore ์ผ ๋ P ์ฐ์ฐ
}
void putdown(int i) {
state[i] = thinking;
test((i + 1) % 5);
test((i - 1) % 5);
}
void test(int i) {
if (state[(i - 1) % 5] != eating && state[i] == hungry && state[(i + 1) % 5] != eating) {
state[i] = eating;
self[i].signal(); // ์ ๋ค์ด ์๋ค๋ฉด ๊นจ์
}
}
void init() {
for (int i = 0; i < 5; i++)
state[i] = thinking;
}
}
Philosopher {
do {
pickup(i); // ๋ชจ๋ํฐ ๋ด๋ถ ์ฐ์ฐ์ ์ด์ฉ
eat();
putdown(i); // ๋ชจ๋ํฐ ๋ด๋ถ ์ฐ์ฐ์ ์ด์ฉ
think();
} while(1);
}
'๐ฅ CS > ์ด์์ฒด์ ' ์นดํ ๊ณ ๋ฆฌ์ ๋ค๋ฅธ ๊ธ
[์ด์์ฒด์ ] ๊ต์ฐฉ ์ํ (Deadlock) (2) | 2023.06.09 |
---|---|
[์ด์์ฒด์ ] ํ๋ก์ธ์ค ๋๊ธฐํ (1/2) (0) | 2023.06.08 |
[์ด์์ฒด์ ] CPU ์ค์ผ์ค๋ง (0) | 2023.03.09 |
[์ด์์ฒด์ ] ์ค๋ ๋ (Thread) (0) | 2023.02.24 |
[์ด์์ฒด์ ] ํ๋ก์ธ์ค ๊ด๋ฆฌ (0) | 2023.02.16 |