๋ณธ๋ฌธ ๋ฐ”๋กœ๊ฐ€๊ธฐ

๐Ÿ–ฅ CS/์šด์˜์ฒด์ œ

[์šด์˜์ฒด์ œ] ํ”„๋กœ์„ธ์Šค ๋™๊ธฐํ™” (2/2)

๋ณธ ๊ฒŒ์‹œ๊ธ€์€ 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);
}