DevLog ๐Ÿ“จ

[CS][Study] Monitor & Conditional Variable

cece00 2024. 1. 11. 13:06

์กฐ๊ฑด๋ณ€์ˆ˜๋ž€? ๋™๊ธฐํ™” ๋ฉ”์ปค๋‹ˆ์ฆ˜ ์ค‘ ์„ธ๋งˆํฌ์–ด์™€ ๋ฎคํ…์Šค, ๋ฝ์€ ์ต์ˆ™ํ•œ๋ฐ ์—ฌ๊ธฐ์„œ ์•ฝ๊ฐ„ ๋” ์‹ฌํ™”ํ•œ๋‹ค๋ฉด ๋‚˜์˜ฌ ์ˆ˜ ์žˆ๋Š” ๊ฒŒ ์กฐ๊ฑด๋ณ€์ˆ˜๋‹ค. ์ƒ์„ฑ์ž-์†Œ๋น„์ž ๋ฌธ์ œ์™€ ๊ด€๋ จํ•ด ์‚ฌ์šฉ๋  ์ˆ˜ ์žˆ๋‹ค.

1. Monitor

๋™์‹œ์„ฑ ํ”„๋กœ๊ทธ๋ž˜๋ฐ์—์„œ, ๋ชจ๋‹ˆํ„ฐ๋Š” ์Šค๋ ˆ๋“œ๊ฐ€ ๊ณต์œ  ๊ฐ์ œ์˜ ์ƒํƒœ์— ๋™์‹œ์ ์œผ๋กœ ์ ‘๊ทผํ•˜๋Š” ๊ฒƒ์„ ๋ง‰๊ณ  ํ•ด๋‹น ์ƒํƒœ๊ฐ€ ๋ณ€๊ฒฝ๋˜์–ด ์กฐ๊ฑด์ด ์ถฉ์กฑ๋  ๋•Œ๊นŒ์ง€ ๋Œ€๊ธฐํ•  ์ˆ˜ ์žˆ๋„๋ก ํ•˜๋Š” ๋™๊ธฐํ™” ๊ตฌ์กฐ์ด๋‹ค. ์ฆ‰, ์ ‘๊ทผ ๊ฐ€๋Šฅํ•œ ์Šค๋ ˆ๋“œ์˜ ์ˆ˜๋ฅผ ์ œํ•œํ•˜๋Š” ์„ธ๋งˆํฌ์–ด๋‚˜ ์ผ๋ฐ˜ ๋ฎคํ…์Šค์™€ ๋‹ค๋ฅด๊ฒŒ, ๋ชจ๋‹ˆํ„ฐ๋Š” ํŠน์ • ์กฐ๊ฑด์˜ ์ถฉ์กฑ์„ ๊ธฐ์ค€์œผ๋กœ ๊ณต์œ  ์ž์›์— ๋Œ€ํ•œ ๋…์ ์ ์ธ ์•ก์„ธ์Šค๋ฅผ ์ œ๊ณตํ•œ๋‹ค. (ํ•œ ๋ฒˆ์— ํ•˜๋‚˜์˜ ์Šค๋ ˆ๋“œ๋งŒ ์ ‘๊ทผํ•  ์ˆ˜ ์žˆ๋‹ค.) ์ผ๋ฐ˜์ ์œผ๋กœ ๋ฝ๊ณผ ํ•˜๋‚˜ ์ด์ƒ์˜ ์กฐ๊ฑด ๋ณ€์ˆ˜๋กœ ๊ตฌ์„ฑ๋œ๋‹ค.

2. Conditional Variable

์กฐ๊ฑด ๋ณ€์ˆ˜๋Š” ํ•ด๋‹น ์กฐ๊ฑด์˜ ์ถฉ์กฑ์„ ๋Œ€๊ธฐํ•˜๊ณ  ์žˆ๋Š” ๋Œ€๊ธฐ์—ด๋กœ ๊ตฌ์„ฑ๋œ๋‹ค. ์กฐ๊ฑด ๋ณ€์ˆ˜๋Š” ํ•ด๋‹น ์ƒํƒœ๊ฐ€ ๋ณ€๊ฒฝ๋  ๋•Œ ๋ช…์‹œ์ ์œผ๋กœ ์‹œ๊ทธ๋„์„ ๋ณด๋‚ด ๋Œ€๊ธฐ์—ด์— ์žˆ๋Š” ์Šค๋ ˆ๋“œ ์ค‘ ์ผ๋ถ€ ๋˜๋Š” ์ „๋ถ€๋ฅผ wakeํ•œ๋‹ค.

wait(condvar, lock)

๋งŒ์•ฝ ์กฐ๊ฑด๋ณ€์ˆ˜๊ฐ€ ์ฐธ์ด ์•„๋‹ˆ๋ผ๋ฉด, ๋ชจ๋‹ˆํ„ฐ๋ฅผ ํš๋“ํ•  ์ˆ˜ ์—†์œผ๋ฏ€๋กœ wait ์—ฐ์‚ฐ์„ ์‹คํ–‰ํ•˜๊ฒŒ ๋œ๋‹ค. ์Šค๋ ˆ๋“œ์˜ ์ƒํƒœ๊ฐ€ Running์—์„œ Block๋กœ ๋ณ€๊ฒฝ๋˜๊ณ , condvar์˜ ๋Œ€๊ธฐ์—ด๋กœ ์ด๋™๋˜์–ด ๋ธ”๋ฝ๋œ๋‹ค.

signal(condvar)

์กฐ๊ฑด๋ณ€์ˆ˜๊ฐ€ ์ฐธ์ด ๋˜๋ฉด ๋ชจ๋‹ˆํ„ฐ๋ฅผ ํš๋“ํ•œ ์Šค๋ ˆ๋“œ์— ์˜ํ•ด ํ˜ธ์ถœ๋œ๋‹ค. ๋Œ€๊ธฐ์—ด์—์„œ ํ•˜๋‚˜์˜ ์Šค๋ ˆ๋“œ๋ฅผ ์„ ํƒํ•ด ๊นจ์šฐ๋Š” ์—ฐ์‚ฐ์œผ๋กœ, ๊ตฌ์ฒด์ ์œผ๋กœ๋Š” ์ƒํƒœ๋ฅผ Block์—์„œ Ready๋กœ ๋ณ€๊ฒฝํ•œ ํ›„ ์Šค์ผ€์ค„๋ง์„ ์œ„ํ•œ ๋Œ€๊ธฐ ํ๋กœ ์ด๋™์‹œํ‚จ๋‹ค. ์–ด๋Š ์Šค๋ ˆ๋“œ๋ฅผ ๊นจ์šธ์ง€๋Š” ๊ตฌํ˜„ ์ •์ฑ…์— ๋”ฐ๋ผ ๋‹ฌ๋ผ์ง€๋Š”๋ฐ, FIFO๋ฅผ ์“ธ์ˆ˜๋„ ์žˆ๊ณ  ์šฐ์„ ์ˆœ์œ„ ์Šค์ผ€์ค„๋ง์—์„œ๋Š” ์šฐ์„ ์ˆœ์œ„ ์ˆœ์ผ์ˆ˜๋„ ์žˆ๋‹ค.

broadcast(condvar)

signal๊ณผ ์œ ์‚ฌํ•˜์ง€๋งŒ, ํ•ด๋‹น ์กฐ๊ฑด๋ณ€์ˆ˜์˜ ๋ชจ๋“  ์Šค๋ ˆ๋“œ๋ฅผ ๊นจ์šด๋‹ค๋Š” ์ ์ด ๋‹ค๋ฅด๋‹ค. ๊นจ์–ด๋‚œ ์Šค๋ ˆ๋“œ๋Š” ๋Œ€๊ธฐ์—ด์—์„œ ๋‚˜์˜จ ์ˆœ์œผ๋กœ ๋ฝ์˜ ํš๋“์„ ์‹œ๋„ํ•˜๊ณ , ๋‚˜๋จธ์ง€ ์Šค๋ ˆ๋“œ๋Š” ํ•ด๋‹น ๋ฝ์˜ ๋Œ€๊ธฐ์—ด๋กœ ๋“ค์–ด๊ฐ„๋‹ค.

3. Producer-Consumer Problem

์ž‘์—… ํ์™€ ์ƒ์‚ฐ์ž, ์†Œ๋น„์ž ์Šค๋ ˆ๋“œ๊ฐ€ ์žˆ๋‹ค๊ณ  ํ•˜์ž. ์ƒ์‚ฐ์ž ์Šค๋ ˆ๋“œ๋Š” ํ์— ์ž‘์—…์„ ์ถ”๊ฐ€ํ•˜๊ณ  ์†Œ๋น„์ž ์Šค๋ ˆ๋“œ๋Š” ํ์—์„œ ์ž‘์—…์„ ๊บผ๋‚ธ๋‹ค. ์ด ํ๋ฅผ thread safeํ•˜๋„๋ก ํ•˜๋ ค๋ฉด ์–ด๋–ป๊ฒŒ ํ•ด์•ผ ํ• ๊นŒ?

์ผ๋‹จ ๋งŒ์•ฝ ํ์— ๋Œ€ํ•œ ์ƒํ˜ธ ๋ฐฐ์ œ๊ฐ€ ์—†๋‹ค๋ฉด ์–ด๋–ป๊ฒŒ ๋ ๊นŒ? ํ์— ์ ‘๊ทผํ•  ๋•Œ์˜ ํ์˜ ์ƒํƒœ๊ฐ€ ์ผ๊ด€๋˜์ง€ ์•Š์„ ์ˆ˜ ์žˆ๋‹ค. ์ƒ์‚ฐ ํ˜น์€ ์†Œ๋น„ ์ ‘๊ทผ์ด ์›์ž์ ์œผ๋กœ ์ด๋ฃจ์–ด์ง€์ง€ ์•Š๊ธฐ ๋•Œ๋ฌธ์ด๋‹ค. ์ด๋Ÿฌํ•œ ์ƒํƒœ๋ฅผ race condition์ด๋ผ๊ณ  ํ•œ๋‹ค.

๊ทธ๋ž˜์„œ ํ์— ๋ฝ์„ ๊ฑธ์–ด ์ƒํ˜ธ ๋ฐฐ์ œ๋ฅผ ๊ตฌํ˜„ํ–ˆ๋‹ค. ํ•˜์ง€๋งŒ ํ์— ๋Œ€ํ•œ ์ ‘๊ทผ์„ ์ƒํ˜ธ ๋ฐฐ์ œํ•˜๋Š” ๊ฒƒ์œผ๋กœ๋Š” ๋ถ€์กฑํ•˜๋‹ค. ์—ฌ๋Ÿฌ ์ƒ์‚ฐ์ž ์Šค๋ ˆ๋“œ๊ฐ€ ํ๊ฐ€ ๊ฐ€๋“ ์ฐผ์Œ์—๋„ ๋ถˆ๊ตฌํ•˜๊ณ  ๋Œ์•„๊ฐ€๋ฉด์„œ ํ์— ์‚ฝ์ž…์„ ์‹œ๋„ํ•  ์ˆ˜ ์žˆ๊ธฐ ๋•Œ๋ฌธ์ด๋‹ค.

์ฆ‰, ๋‹จ์ง€ ์ ‘๊ทผ ์ œ์–ด๊ฐ€ ์•„๋‹ˆ๋ผ ํ์˜ ์ƒํƒœ (is_full, is_empty)๋ฅผ ๋ณด์•„์•ผ ํ•œ๋‹ค. ํ์˜ ์ƒํƒœ๋ฅผ ์ฒดํฌํ•˜๋ฉด์„œ busy-waiting ๋ฐฉ์‹์œผ๋กœ ์Šค๋ ˆ๋“œ๋ฅผ ๋Œ€๊ธฐ์‹œํ‚ค๋Š” ์Šคํ•€๋ฝ์„ ์‚ฌ์šฉํ•  ์ˆ˜๋„ ์žˆ์ง€๋งŒ, ๋ช…์‹œ์ ์ธ ๋Œ€๊ธฐ์—ด์„ ๋‘๊ณ  blocking ๋ฐฉ์‹์„ ์‚ฌ์šฉํ•˜๋Š” ๊ฒŒ CPU๋‚ญ๋น„๊ฐ€ ์—†๋‹ค๋Š” ์ ์—์„œ ๋” ์ข‹๋‹ค. ๋”ฐ๋ผ์„œ ์ด๋ฅผ ์œ„ํ•ด ์กฐ๊ฑด๋ณ€์ˆ˜๊ฐ€ ์‚ฌ์šฉ๋  ์ˆ˜ ์žˆ๋‹ค.

// pseudo

bool is_full, is_empt;
cv cv_full;     // full ์ธ ๊ฒฝ์šฐ ์ƒ์‚ฐ์ž ์Šค๋ ˆ๋“œ๊ฐ€ ๋Œ€๊ธฐํ•จ
cv cv_empt;     // empty์ธ ๊ฒฝ์šฐ ์†Œ๋น„์ž ์Šค๋ ˆ๋“œ๊ฐ€ ๋Œ€๊ธฐํ•จ
queue taskq;

void produce(Task t) {
    acquire(taskq.lock);

    while(taskq.is_full) {
        wait(taskq.lock, cv_full);
    }

    taskq.enqueue(t);
    signal(cv_empt);    // ๋Œ€๊ธฐํ•˜๋˜ ์†Œ๋น„์ž ์Šค๋ ˆ๋“œ ๊นจ์›€
    release(taskq.lock);
}

Task consume() {
    acquire(taskq.lock);

    while(taskq.is_empty) {
        wait(taskq.lock, cv_empt);
    }

    Task t = taskq.dequeue();
    signal(cv_full);    // ๋Œ€๊ธฐํ•˜๋˜ ์ƒ์‚ฐ์ž ์Šค๋ ˆ๋“œ ๊นจ์›€
    release(taskq.lock);

    return t;
}

What's more?

Spurious wakeup

์Šค๋ ˆ๋“œ๊ฐ€ ์‹ ํ˜ธ๋ฅผ ๋ฐ›์ง€ ์•Š์•˜๋Š”๋ฐ ๋Œ€๊ธฐ์—์„œ ๊นจ์–ด๋‚˜๋Š” ๊ฒฝ์šฐ๊ฐ€ ์žˆ๋‹ค. (์™œ ๊ทธ๋Ÿฐ๊ฐ€?) ์ด๋Ÿฐ ํ˜„์ƒ์ด ์žˆ์–ด์„œ signalํ•จ์ˆ˜ ์ข…๋ฃŒ ํ›„์— ์‹ค์ œ ์กฐ๊ฑด ๋ณ€์ˆ˜๊ฐ€ ๋ณ€๊ฒฝ๋œ ๊ฒŒ ๋งž๋Š”์ง€ ํ•œ ๋ฒˆ ๋” ๊ฒ€์ฆํ•˜๋Š” ์ฝ”๋“œ๋ฅผ ์‹ฌ์„ ์ˆ˜ ์žˆ๋‹ค. cv_full ์กฐ๊ฑด๋ณ€์ˆ˜์— ๋Œ€ํ•œ signalํ•จ์ˆ˜ ์‹คํ–‰ ํ›„์— !taskq.is_full ์ด true์ธ์ง€ ํ•œ๋ฒˆ ๋” ์ฒดํฌํ•˜๊ณ , ์•„๋‹ ๊ฒฝ์šฐ ๋‹ค์‹œ waitํ•˜๋Š” ์‹์ด๋‹ค.