[Week08] ๐Ÿ”‘ Synchronization ๐Ÿ”

ellaยท2023๋…„ 5์›” 24์ผ
0

๐ŸŒณ์ •๊ธ€ 6๊ธฐ๐ŸŒณ

๋ชฉ๋ก ๋ณด๊ธฐ
36/39
post-thumbnail

default pintOS๋Š” semaphore๋ฅผ ๋Œ€๊ธฐํ•˜๊ณ  ์žˆ๋Š” ์Šค๋ ˆ๋“œ๋“ค์˜ list์œ waieters๊ฐ€ FIFO๋กœ ๊ตฌํ˜„๋˜์–ด์žˆ๋‹ค. ์ด๋ฅผ ์—ฌ๋Ÿฌ ์Šค๋ ˆ๋“œ๊ฐ€ lock, semaphore, condition variable์„ ์–ป๊ธฐ ์œ„ํ•ด ๊ธฐ๋‹ค๋ฆด ๊ฒฝ์šฐ ์šฐ์„ ์ˆœ์œ„๊ฐ€ ๊ฐ€์žฅ ๋†’์€ thread๊ฐ€ CPU๋ฅผ ์ ์œ ํ•˜๋„๋ก ์ˆ˜์ •ํ•ด๋ณด์ž.

๐ŸŒธ๐ŸŒธ๐ŸŒธ๋ธ”๋กœ๊ทธ ๊ธ€์€ ๋ณต์Šต ๊ฒธ gitbook์˜ ์ˆœ์„œ์— ๋”ฐ๋ผ ๋ฒˆ์—ญ ๋ฐ ๊ด€๋ จ ๋‚ด์šฉ์— JKํ”ผ์…œ์„ ๋‹ฌ์•„ ์ •๋ฆฌํ•  ์˜ˆ์ •์ด๋‹ค. ๋ง๊ทธ๋Œ€๋กœ JKํ”ผ์…œ์ธ ์นธํผ 100%๋งž๋Š” ๋ง์€ ์•„๋‹ ์ˆ˜ ์žˆ๋‹ค๋Š” ๊ฑฐ ์ฐธ๊ณ ํ•ด์ฃผ๊ธธ ๋ฐ”๋ž€๋‹ค.


๐Ÿ“– Gitbook ๋‚ด์šฉ(in APPENDIX) ๐Ÿ“–

gitbook์„ ๋‹ค์‹œ ์ฝ์–ด๋ณด๋‹ˆ ์ค‘์š”ํ•œ ๋‚ด์šฉ๋“ค๊ณผ ํžŒํŠธ๋“ค์ด ์ด์•ˆ์— ๋‹ค ์žˆ์—ˆ๋‹ค. ๋ˆˆ ๋จผ ์žฅ๋‹˜์ด๋ผ๋Š”๊ฒŒ ์ด๋Ÿฐ๊ฑด๊ฐ€!

Synchronization

์Šค๋ ˆ๋“œ ๊ฐ„์˜ ์ž์› ๊ณต์œ ๊ฐ€ ์‹ ์ค‘ํ•˜๊ณ  ํ†ต์ œ๋œ ๋ฐฉ์‹์œผ๋กœ ์ฒ˜๋ฆฌ๋˜์ง€ ์•Š์œผ๋ฉด ์ผ๋ฐ˜์ ์œผ๋กœ ํฐ ๋ฌธ์ œ๊ฐ€ ๋ฐœ์ƒํ•ฉ๋‹ˆ๋‹ค. ํŠนํžˆ ์šด์˜ ์ฒด์ œ ์ปค๋„์—์„œ๋Š” ์ž˜๋ชป๋œ ๊ณต์œ ๋กœ ์ธํ•ด ์ „์ฒด ์‹œ์Šคํ…œ์ด ์ถฉ๋Œํ•  ์ˆ˜ ์žˆ์Šต๋‹ˆ๋‹ค. Pintos๋Š” ์ด๋Ÿฌํ•œ ๋ฌธ์ œ๋ฅผ ํ•ด๊ฒฐํ•˜๊ธฐ ์œ„ํ•ด ์—ฌ๋Ÿฌ ๋™๊ธฐํ™” ๊ธฐ๋ณธ ์š”์†Œ๋ฅผ ์ œ๊ณตํ•ฉ๋‹ˆ๋‹ค.

Disabling Interrupts

๊ฐ€์žฅ ์›์‹œ์ ์ธ ๋™๊ธฐํ™” ๋ฐฉ๋ฒ•์€ ์ธํ„ฐ๋ŸฝํŠธ๋ฅผ ๋น„ํ™œ์„ฑํ™”ํ•˜๋Š” ๊ฒƒ์ž…๋‹ˆ๋‹ค. ์ฆ‰, CPU๊ฐ€ ์ธํ„ฐ๋ŸฝํŠธ์— ์‘๋‹ตํ•˜์ง€ ๋ชปํ•˜๋„๋ก ์ผ์‹œ์ ์œผ๋กœ ๋ง‰๋Š” ๊ฒƒ์ž…๋‹ˆ๋‹ค. ์ธํ„ฐ๋ŸฝํŠธ๊ฐ€ ๊บผ์ ธ ์žˆ์œผ๋ฉด ๋‹ค๋ฅธ ์Šค๋ ˆ๋“œ๋Š” ์‹คํ–‰ ์ค‘์ธ ์Šค๋ ˆ๋“œ๋ฅผ ์„ ์ ํ•˜์ง€ ์•Š์Šต๋‹ˆ๋‹ค. ์™œ๋ƒํ•˜๋ฉด ์Šค๋ ˆ๋“œ ์„ ์ ์€ ํƒ€์ด๋จธ ์ธํ„ฐ๋ŸฝํŠธ์— ์˜ํ•ด ์ œ์–ด๋˜๊ธฐ ๋•Œ๋ฌธ์ž…๋‹ˆ๋‹ค. ์ธํ„ฐ๋ŸฝํŠธ๊ฐ€ ์ผœ์ ธ ์žˆ๋Š” ๊ฒฝ์šฐ, ์ผ๋ฐ˜์ ์œผ๋กœ ๊ทธ๋ ‡์Šต๋‹ˆ๋‹ค. ์‹คํ–‰ ์ค‘์ธ ์Šค๋ ˆ๋“œ๋Š” ๋‘ ๊ฐœ์˜ C ๋ฌธ ์‚ฌ์ด ๋˜๋Š” ํ•˜๋‚˜์˜ ์‹คํ–‰ ๋‚ด์—์„œ๋„ ์–ธ์ œ๋“ ์ง€ ๋‹ค๋ฅธ ์Šค๋ ˆ๋“œ์— ์˜ํ•ด ์„ ์ ๋  ์ˆ˜ ์žˆ์Šต๋‹ˆ๋‹ค.

๊ทธ๋Ÿฐ ๊ด€์ ์—์„œ Pintos๋Š” "์„ ์  ๊ฐ€๋Šฅํ•œ ์ปค๋„(preemptible kernel)" ์ž…๋‹ˆ๋‹ค. ์ฆ‰, ์ปค๋„ ์Šค๋ ˆ๋“œ๋Š” ์–ธ์ œ๋“ ์ง€ ์„ ์ ๋  ์ˆ˜ ์žˆ์Šต๋‹ˆ๋‹ค. ์ „ํ†ต์ ์ธ Unix ์‹œ์Šคํ…œ์€ "๋น„์„ ์  ๊ฐ€๋Šฅํ•œ(nonpreemptible)" ์ปค๋„์ด๋ผ๊ณ  ํ•  ์ˆ˜ ์žˆ์Šต๋‹ˆ๋‹ค. ์ฆ‰, ์ปค๋„ ์Šค๋ ˆ๋“œ๋Š” ๋ช…์‹œ์ ์œผ๋กœ ์Šค์ผ€์ค„๋Ÿฌ๋ฅผ ํ˜ธ์ถœํ•˜๋Š” ์ง€์ ์—์„œ๋งŒ ์„ ์ ๋  ์ˆ˜ ์žˆ์Šต๋‹ˆ๋‹ค. (์‚ฌ์šฉ์ž ํ”„๋กœ๊ทธ๋žจ์€ ๋‘ ๋ชจ๋ธ ๋ชจ๋‘์—์„œ ์–ธ์ œ๋“ ์ง€ ์„ ์ ๋  ์ˆ˜ ์žˆ์Šต๋‹ˆ๋‹ค.) ์„ ์  ๊ฐ€๋Šฅํ•œ ์ปค๋„์€ ๋ช…์‹œ์ ์ธ ๋™๊ธฐํ™”๊ฐ€ ๋” ํ•„์š”ํ•˜๋‹ค๋Š” ์ ์—์„œ ์ƒ์ƒํ•  ์ˆ˜ ์žˆ์Šต๋‹ˆ๋‹ค.

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

๋ช‡๊ฐ€์ง€ ์™ธ๋ถ€ ์ธํ„ฐ๋ŸฝํŠธ๋Š” ์ธํ„ฐ๋ŸฝํŠธ ๋น„ํ™œ์„ฑํ™”๋กœ๋„ ๋ง‰์•„๋‘˜ ์ˆ˜ ์—†์Šต๋‹ˆ๋‹ค. ์ด๋Ÿฐ ์ธํ„ฐ๋ŸฝํŠธ๋“ค์€ ๋งˆ์Šคํฌ ๋ถˆ๊ฐ€๋Šฅ ์ธํ„ฐ๋ŸฝํŠธ(NMIs) ๋ผ๊ณ  ํ•˜๋Š”๋ฐ, ์ปดํ“จํ„ฐ๊ฐ€ ๋ถˆ์ด๋‚ฌ์„ ๋•Œ(ํ™”์žฌ์ƒํ™ฉ)์ฒ˜๋Ÿผ ๊ธด๊ธ‰ํ•œ ๊ฒฝ์šฐ์—๋งŒ ์‚ฌ์šฉ๋˜์–ด์•ผ ํ•ฉ๋‹ˆ๋‹ค. Pintos๋Š” ๋งˆ์Šคํฌ ๋ถˆ๊ฐ€๋Šฅ ์ธํ„ฐ๋ŸฝํŠธ๋ฅผ ๋‹ค๋ฃจ์ง€ ์•Š์Šต๋‹ˆ๋‹ค.

์ธํ„ฐ๋ŸฝํŠธ๋ฅผ ๋น„ํ™œ์„ฑํ™”ํ•˜๊ณ  ํ™œ์„ฑํ™”ํ•˜๊ธฐ ์œ„ํ•œ ์œ ํ˜•๊ณผ ํ•จ์ˆ˜๋Š” include/threads/interrupt.h์— ์ •์˜๋˜์–ด ์žˆ์Šต๋‹ˆ๋‹ค.

INTR_OFF ๋˜๋Š” INTR_ON ์ค‘ ํ•˜๋‚˜๋กœ, ๊ฐ๊ฐ ์ธํ„ฐ๋ŸฝํŠธ๊ฐ€ ๋น„ํ™œ์„ฑํ™”๋˜์—ˆ๊ฑฐ๋‚˜ ํ™œ์„ฑํ™”๋˜์—ˆ์Œ์„ ๋‚˜ํƒ€๋ƒ…๋‹ˆ๋‹ค.

enum intr_level;

ํ˜„์žฌ ์ธํ„ฐ๋ŸฝํŠธ ์ƒํƒœ(inter_level)๋ฅผ ๋ฆฌํ„ดํ•˜๋Š” ํ•จ์ˆ˜์ž…๋‹ˆ๋‹ค.

enum intr_level intr_get_level (void)

ํ˜„์žฌ ์ƒํƒœ(inter_level)์— ๋”ฐ๋ผ ์ธํ„ฐ๋ŸฝํŠธ๋ฅผ ํ™œ์„ฑํ™”ํ•˜๊ฑฐ๋‚˜ ๋น„ํ™œ์„ฑํ™”ํ•˜๋Š” ํ•จ์ˆ˜์ž…๋‹ˆ๋‹ค. ์ธํ„ฐ๋ŸฝํŠธ์˜ ์ด์ „ ์ƒํƒœ๋ฅผ ๋ฆฌํ„ดํ•ฉ๋‹ˆ๋‹ค.

enum intr_level intr_set_level (enum intr_level level);

์ธํ„ฐ๋ŸฝํŠธ๋ฅผ ํ™œ์„ฑํ™”ํ•˜๋Š” ํ•จ์ˆ˜์ž…๋‹ˆ๋‹ค. ์ธํ„ฐ๋ŸฝํŠธ์˜ ์ด์ „ ์ƒํƒœ๋ฅผ ๋ฆฌํ„ดํ•ฉ๋‹ˆ๋‹ค.

enum intr_level intr_enable (void);

์ธํ„ฐ๋ŸฝํŠธ๋ฅผ ๋น„ํ™œ์„ฑํ™” ํ•ด์ฃผ๋Š” ํ•จ์ˆ˜์ž…๋‹ˆ๋‹ค. ์ธํ„ฐ๋ŸฝํŠธ์˜ ์ด์ „ ์ƒํƒœ๋ฅผ ๋ฆฌํ„ดํ•ฉ๋‹ˆ๋‹ค.

enum intr_level intr_disable (void);

Semaphores

์„ธ๋งˆํฌ์–ด๋Š” 0 ์ด์ƒ์˜ ์ •์ˆ˜์™€ ํ•จ๊ป˜ ์‚ฌ์šฉ๋˜๋Š” ๋‘ ๊ฐ€์ง€ atomicํ•œ(race condition์ด ์—†๋„๋ก ํ•œ๊ฐ€์ง€๋งŒ ์ ‘๊ทผํ•˜๋„๋ก ํ•œ) ์กฐ์ž‘ ์—ฐ์‚ฐ์ธ "Down" ๋˜๋Š” "P"์™€ "UP" ๋˜๋Š” "V"๋กœ ๊ตฌ์„ฑ๋ฉ๋‹ˆ๋‹ค. ์ด ์—ฐ์‚ฐ์ž๋“ค์€ ๋‹ค์Œ๊ณผ ๊ฐ™์€ ์—ญํ• ์„ ์ˆ˜ํ–‰ํ•ฉ๋‹ˆ๋‹ค:

  • "Down" ๋˜๋Š” "P": ๊ฐ’์ด ์–‘์ˆ˜๊ฐ€ ๋  ๋•Œ๊นŒ์ง€ ๋Œ€๊ธฐํ•œ ํ›„ ๊ฐ’์„ ๊ฐ์†Œ์‹œํ‚ต๋‹ˆ๋‹ค.
  • "UP" ๋˜๋Š” "V": ๊ฐ’์„ ์ฆ๊ฐ€์‹œํ‚ต๋‹ˆ๋‹ค (๊ทธ๋ฆฌ๊ณ  ๋Œ€๊ธฐ ์ค‘์ธ ์Šค๋ ˆ๋“œ ์ค‘ ํ•˜๋‚˜๋ฅผ ๊นจ์›๋‹ˆ๋‹ค).

0์œผ๋กœ ์ดˆ๊ธฐํ™”๋œ ์„ธ๋งˆํฌ์–ด๋Š” ์ •ํ™•ํžˆ ํ•œ ๋ฒˆ ๋ฐœ์ƒํ•  ์ด๋ฒคํŠธ๋ฅผ ๊ธฐ๋‹ค๋ฆฌ๋Š” ๋ฐ ์‚ฌ์šฉ๋  ์ˆ˜ ์žˆ์Šต๋‹ˆ๋‹ค. ์˜ˆ๋ฅผ ๋“ค์–ด, ์Šค๋ ˆ๋“œ A๊ฐ€ ๋‹ค๋ฅธ ์Šค๋ ˆ๋“œ B๋ฅผ ์‹œ์ž‘ํ•˜๊ณ  B๊ฐ€ ์–ด๋–ค ์ž‘์—…์ด ์™„๋ฃŒ๋  ๋•Œ๊นŒ์ง€ ๊ธฐ๋‹ค๋ฆฌ๋ ค๊ณ  ํ•  ๋•Œ, A๋Š” 0์œผ๋กœ ์ดˆ๊ธฐํ™”๋œ ์„ธ๋งˆํฌ์–ด๋ฅผ ์ƒ์„ฑํ•˜๊ณ  B์—๊ฒŒ ์ „๋‹ฌํ•œ ํ›„ ์„ธ๋งˆํฌ์–ด๋ฅผ "down"ํ•ฉ๋‹ˆ๋‹ค. B๊ฐ€ ์ž‘์—…์„ ์™„๋ฃŒํ•˜๋ฉด ์„ธ๋งˆํฌ์–ด๋ฅผ "up"ํ•ฉ๋‹ˆ๋‹ค. A๊ฐ€ ์„ธ๋งˆํฌ์–ด๋ฅผ "down"ํ•˜๊ฑฐ๋‚˜ B๊ฐ€ "up"ํ•˜๋Š” ์ˆœ์„œ์— ์ƒ๊ด€์—†์ด ์ด ๋ฐฉ๋ฒ•์€ ์ž‘๋™ํ•ฉ๋‹ˆ๋‹ค.

์˜ˆ์‹œ:

struct semaphore sema;

/* Thread A */
void threadA (void) {
    sema_down (&sema);
}

/* Thread B */
void threadB (void) {
    sema_up (&sema);
}

/* main function */
void main (void) {
    sema_init (&sema, 0);
    thread_create ("threadA", PRI_MIN, threadA, NULL);
    thread_create ("threadB", PRI_MIN, threadB, NULL);
}

์ด ์˜ˆ์‹œ์—์„œ, threadA๋Š” sema_down() ํ•จ์ˆ˜๋ฅผ ์‚ฌ์šฉํ•˜์—ฌ threadB๊ฐ€ sema_up() ํ•จ์ˆ˜๋ฅผ ํ˜ธ์ถœํ•  ๋•Œ๊นŒ์ง€ ์‹คํ–‰์„ ๋ฉˆ์ถฅ๋‹ˆ๋‹ค.

1๋กœ ์ดˆ๊ธฐํ™”๋œ ์„ธ๋งˆํฌ์–ด๋Š” ์ฃผ๋กœ ๋ฆฌ์†Œ์Šค ์ ‘๊ทผ์„ ์ œ์–ดํ•˜๋Š” ๋ฐ ์‚ฌ์šฉ๋ฉ๋‹ˆ๋‹ค. ๋ฆฌ์†Œ์Šค๋ฅผ ์‚ฌ์šฉํ•˜๊ธฐ ์ „์— ํ•ด๋‹นํ•˜๋Š” ์ฝ”๋“œ ๋ธ”๋ก์€ ์„ธ๋งˆํฌ์–ด๋ฅผ "down" (๊ฐ์†Œ)์‹œํ‚ค๊ณ , ๋ฆฌ์†Œ์Šค ์‚ฌ์šฉ์ด ๋๋‚˜๋ฉด "up" (์ฆ๊ฐ€)์‹œํ‚ต๋‹ˆ๋‹ค. ์ด๋Ÿฌํ•œ ๊ฒฝ์šฐ์—๋Š” ๋ฝ (lock)์ด ๋” ์ ํ•ฉํ•  ์ˆ˜ ์žˆ์Šต๋‹ˆ๋‹ค.

์„ธ๋งˆํฌ์–ด๋Š” 1๋ณด๋‹ค ํฐ ๊ฐ’์„ ๊ฐ€์ง€๋„๋ก ์ดˆ๊ธฐํ™”๋  ์ˆ˜๋„ ์žˆ์Šต๋‹ˆ๋‹ค. ๊ทธ๋Ÿฌ๋‚˜ ์ด๋Ÿฌํ•œ ๊ฒฝ์šฐ๋Š” ๋“œ๋ฌผ๊ฒŒ ์‚ฌ์šฉ๋ฉ๋‹ˆ๋‹ค. ์„ธ๋งˆํฌ์–ด๋Š” Edsger Dijkstra๊ฐ€ ๊ฐœ๋ฐœํ•œ ๊ฒƒ์œผ๋กœ, THE ์šด์˜ ์ฒด์ œ์—์„œ ์ฒ˜์Œ ์‚ฌ์šฉ๋˜์—ˆ์Šต๋‹ˆ๋‹ค. Pintos์˜ ์„ธ๋งˆํฌ์–ด ํƒ€์ž…๊ณผ ์—ฐ์‚ฐ์€ include/threads/synch.h ํ—ค๋” ํŒŒ์ผ์— ์„ ์–ธ๋˜์–ด ์žˆ์Šต๋‹ˆ๋‹ค.

์„ธ๋งˆํฌ์–ด๋ฅผ ๋‚˜ํƒ€๋ƒ…๋‹ˆ๋‹ค.

struct semaphore;

์ฃผ์–ด์ง„ ์ดˆ๊ธฐ๊ฐ’์„ ๊ฐ€์ง€๊ณ  ์ƒˆ๋กœ์šด ์„ธ๋งˆํฌ์–ด๋ฅผ ์ดˆ๊ธฐํ™”ํ•ฉ๋‹ˆ๋‹ค.

void sema_init (struct semaphore *sema, unsigned value);

sema์— ๋Œ€ํ•ด "down" ๋˜๋Š” "P" ์—ฐ์‚ฐ์„ ์ˆ˜ํ–‰ํ•˜์—ฌ ๊ฐ’์ด ์–‘์ˆ˜๊ฐ€ ๋  ๋•Œ๊นŒ์ง€ ๊ธฐ๋‹ค๋ฆฌ๊ณ , ๊ทธ ํ›„์— ๊ฐ’์„ 1 ๊ฐ์†Œ์‹œํ‚ต๋‹ˆ๋‹ค.

void sema_down (struct semaphore *sema);

sema์— ๋Œ€ํ•ด "down" ๋˜๋Š” "P" ์—ฐ์‚ฐ์„ ์‹œ๋„ํ•˜๋ฉฐ, ๋Œ€๊ธฐํ•˜์ง€ ์•Š์Šต๋‹ˆ๋‹ค. sema๊ฐ€ ์„ฑ๊ณต์ ์œผ๋กœ ๊ฐ์†Œ๋˜๋ฉด true๋ฅผ ๋ฐ˜ํ™˜ํ•˜๊ณ , ์ด๋ฏธ 0์ด๊ธฐ ๋•Œ๋ฌธ์— ๋Œ€๊ธฐ ์—†์ด ๊ฐ์†Œํ•  ์ˆ˜ ์—†๋Š” ๊ฒฝ์šฐ false๋ฅผ ๋ฐ˜ํ™˜ํ•ฉ๋‹ˆ๋‹ค. ์ด ํ•จ์ˆ˜๋ฅผ ๋ฐ˜๋ณต๋ฌธ ์•ˆ์—์„œ ๊ณ„์† ํ˜ธ์ถœํ•˜๋Š” ๊ฒƒ์€ CPU ์‹œ๊ฐ„์„ ๋‚ญ๋น„ํ•˜๋ฏ€๋กœ, sema_down()๋ฅผ ์‚ฌ์šฉํ•˜๊ฑฐ๋‚˜ ๋‹ค๋ฅธ ์ ‘๊ทผ ๋ฐฉ์‹์„ ์ฐพ๋Š” ๊ฒƒ์ด ์ข‹์Šต๋‹ˆ๋‹ค.

bool sema_try_down (struct semaphore *sema);

sema์— ๋Œ€ํ•ด "up" ๋˜๋Š” "V" ์—ฐ์‚ฐ์„ ์‹คํ–‰ํ•˜์—ฌ ๊ฐ’์„ ์ฆ๊ฐ€์‹œํ‚ต๋‹ˆ๋‹ค. sema์— ๋Œ€๊ธฐ ์ค‘์ธ ์Šค๋ ˆ๋“œ๊ฐ€ ์žˆ๋‹ค๋ฉด ๊ทธ ์ค‘ ํ•˜๋‚˜๋ฅผ ๊นจ์›๋‹ˆ๋‹ค. ๋Œ€๋ถ€๋ถ„์˜ ๋™๊ธฐํ™” ๊ธฐ๋ฒ•๊ณผ๋Š” ๋‹ฌ๋ฆฌ, sema_up()์€ ์™ธ๋ถ€ ์ธํ„ฐ๋ŸฝํŠธ ํ•ธ๋“ค๋Ÿฌ ๋‚ด์—์„œ ํ˜ธ์ถœ๋  ์ˆ˜ ์žˆ์Šต๋‹ˆ๋‹ค.

void sema_up (struct semaphore *sema);

์„ธ๋งˆํฌ์–ด๋Š” ์ธํ„ฐ๋ŸฝํŠธ ๋น„ํ™œ์„ฑํ™”(disabling interrupt) ๋ฐ ์Šค๋ ˆ๋“œ์˜ ์ฐจ๋‹จ ๋ฐ ์ฐจ๋‹จ ํ•ด์ œ(thread_block() ๋ฐ thread_unblock())๋ฅผ ๋‚ด๋ถ€์ ์œผ๋กœ ์‚ฌ์šฉํ•˜์—ฌ ๊ตฌ์ถ•๋ฉ๋‹ˆ๋‹ค. ๊ฐ ์„ธ๋งˆํฌ์–ด๋Š” lib/kernel/list.c์˜ ์—ฐ๊ฒฐ ๋ฆฌ์ŠคํŠธ ๊ตฌํ˜„์„ ์‚ฌ์šฉํ•˜์—ฌ ๋Œ€๊ธฐ ์ค‘์ธ ์Šค๋ ˆ๋“œ์˜ ๋ชฉ๋ก์„ ์œ ์ง€ํ•ฉ๋‹ˆ๋‹ค.

Locks

๋ฝ์€ ์ดˆ๊ธฐ ๊ฐ’์ด 1์ธ ์„ธ๋งˆํฌ์–ด์™€ ์œ ์‚ฌํ•ฉ๋‹ˆ๋‹ค(์„ธ๋งˆํฌ์–ด ์ฐธ์กฐ). ๋ฝ์˜ "up"๊ณผ ๋™๋“ฑํ•œ ์ž‘์—…์€ "release"๋กœ ๋ถˆ๋ฆฌ๋ฉฐ, "down" ์ž‘์—…์€ "acquire"๋กœ ๋ถˆ๋ฆฝ๋‹ˆ๋‹ค.

์„ธ๋งˆํฌ์–ด์™€ ๋น„๊ตํ•˜์—ฌ ๋ฝ์€ ์ถ”๊ฐ€์ ์ธ ์ œํ•œ์ด ์žˆ์Šต๋‹ˆ๋‹ค: ์˜ค์ง, ๋ฝ์„ ๊ฐ–๊ณ ์žˆ๋Š” โ€œownerโ€ ์“ฐ๋ ˆ๋“œ๋งŒ์ด ๋ฝ์„ ๋†“์•„์ค„ ์ˆ˜ ์žˆ์Šต๋‹ˆ๋‹ค. ๋งŒ์•ฝ ์ด ์ œ์•ฝ๋•Œ๋ฌธ์— ๋ฌธ์ œ๊ฐ€ ๋˜๋Š” ๊ฒฝ์šฐ๋Š” ๋ฝ๋Œ€์‹ ์— ์„ธ๋งˆํฌ์–ด๋ฅผ ์จ์•ผํ•œ๋‹ค๋Š” ์ข‹์€ ์‹ ํ˜ธ์ž…๋‹ˆ๋‹ค.

Pintos์—์„œ์˜ ๋ฝ์€ "์žฌ๊ท€์ (recursive)"์ด ์•„๋‹™๋‹ˆ๋‹ค. ์ฆ‰, ํ˜„์žฌ ๋ฝ์„ ์†Œ์œ ํ•œ ์Šค๋ ˆ๋“œ๊ฐ€ ํ•ด๋‹น ๋ฝ์„ ๋‹ค์‹œ ํš๋“ํ•˜๋ ค๊ณ  ์‹œ๋„ํ•˜๋Š” ๊ฒƒ์€ ์˜ค๋ฅ˜์ž…๋‹ˆ๋‹ค. ๋ฝ์˜ ์œ ํ˜•๊ณผ ํ•จ์ˆ˜๋Š” include/threads/synch.h์— ์„ ์–ธ๋˜์–ด ์žˆ์Šต๋‹ˆ๋‹ค.

๋ฝ์„ ๋‚˜ํƒ€๋ƒ…๋‹ˆ๋‹ค.

struct lock;

lock์„ ์ƒˆ๋กœ ์ดˆ๊ธฐํ™”ํ•ฉ๋‹ˆ๋‹ค. ์ด ๋ฝ์€ ์ดˆ๊ธฐ ์ƒํƒœ์—์„œ ์–ด๋–ค ์Šค๋ ˆ๋“œ์—๊ฒŒ๋„ ์†Œ์œ ๋˜์ง€ ์•Š์Šต๋‹ˆ๋‹ค.

void lock_init (struct lock *lock);

ํ˜„์žฌ ์Šค๋ ˆ๋“œ๊ฐ€ ๋ฝ์„ ํš๋“ํ•ฉ๋‹ˆ๋‹ค. ํ•„์š”ํ•œ ๊ฒฝ์šฐ ํ˜„์žฌ ์†Œ์œ ์ž๊ฐ€ ๋ฝ์„ ํ•ด์ œํ•  ๋•Œ๊นŒ์ง€ ๋Œ€๊ธฐํ•ฉ๋‹ˆ๋‹ค.

void lock_acquire (struct lock *lock);

ํ˜„์žฌ ์Šค๋ ˆ๋“œ๊ฐ€ ์‚ฌ์šฉํ•˜๊ธฐ ์œ„ํ•ด ๋ฝ์„ ํš๋“ํ•˜๋ ค๊ณ  ์‹œ๋„ํ•ฉ๋‹ˆ๋‹ค. ๋Œ€๊ธฐํ•˜์ง€ ์•Š๊ณ  ๋ฐ”๋กœ ํš๋“ํ•  ์ˆ˜ ์žˆ๋Š” ๊ฒฝ์šฐ true๋ฅผ ๋ฐ˜ํ™˜ํ•˜๊ณ , ์ด๋ฏธ ๋‹ค๋ฅธ ์Šค๋ ˆ๋“œ์— ์˜ํ•ด ์†Œ์œ ๋˜์—ˆ์„ ๊ฒฝ์šฐ false๋ฅผ ๋ฐ˜ํ™˜ํ•ฉ๋‹ˆ๋‹ค. ์ด ํ•จ์ˆ˜๋ฅผ ๋ฐ˜๋ณต์ ์œผ๋กœ ํ˜ธ์ถœํ•˜๋Š” ๊ฒƒ์€ CPU ์‹œ๊ฐ„์„ ๋‚ญ๋น„ํ•˜๋ฏ€๋กœ lock_acquire()๋ฅผ ์‚ฌ์šฉํ•ด์•ผ ํ•ฉ๋‹ˆ๋‹ค.

bool lock_try_acquire (struct lock *lock);

ํ˜„์žฌ ์Šค๋ ˆ๋“œ๊ฐ€ ์†Œ์œ ํ•œ ๋ฝ์„ ํ•ด์ œํ•ฉ๋‹ˆ๋‹ค.

void lock_release (struct lock *lock);

running thread๊ฐ€ lock์„ ์†Œ์œ ํ•˜๋ฉด true๋ฅผ ๋ฐ˜ํ™˜ํ•˜๊ณ , ๊ทธ๋ ‡์ง€ ์•Š์œผ๋ฉด false๋ฅผ ๋ฐ˜ํ™˜ํ•ฉ๋‹ˆ๋‹ค. ์ž„์˜์˜ ์Šค๋ ˆ๋“œ๊ฐ€ lock์„ ์†Œ์œ ํ•˜๋Š”์ง€ ํ…Œ์ŠคํŠธํ•˜๋Š” ํ•จ์ˆ˜๋Š” ์—†์Šต๋‹ˆ๋‹ค. ์™œ๋ƒํ•˜๋ฉด ํ˜ธ์ถœ์ž๊ฐ€ ๊ทธ ๊ฒฐ๊ณผ์— ๋Œ€ํ•œ ์กฐ์น˜๋ฅผ ์ทจํ•˜๊ธฐ ์ „์— ์ƒํ™ฉ์ด ๋ณ€๊ฒฝ๋  ์ˆ˜ ์žˆ๊ธฐ ๋•Œ๋ฌธ์ž…๋‹ˆ๋‹ค.

bool lock_held_by_current_thread (const struct lock *lock):

Monitors

๋ชจ๋‹ˆํ„ฐ๋Š” ์„ธ๋งˆํฌ์–ด๋‚˜ ๋ฝ๋ณด๋‹ค ๋” ๋†’์€ ์ˆ˜์ค€์˜ ๋™๊ธฐํ™” ํ˜•์‹์ž…๋‹ˆ๋‹ค. ๋ชจ๋‹ˆํ„ฐ๋Š” ๋™๊ธฐํ™”๋˜๋Š” ๋ฐ์ดํ„ฐ์™€ ๋ชจ๋‹ˆํ„ฐ ๋ฝ์ด๋ผ๊ณ  ๋ถˆ๋ฆฌ๋Š” ๋ฝ, ๊ทธ๋ฆฌ๊ณ  ํ•˜๋‚˜ ์ด์ƒ์˜ ์กฐ๊ฑด ๋ณ€์ˆ˜๋กœ ๊ตฌ์„ฑ๋ฉ๋‹ˆ๋‹ค. ์Šค๋ ˆ๋“œ๊ฐ€ ๋ณดํ˜ธ๋œ ๋ฐ์ดํ„ฐ์— ์ ‘๊ทผํ•˜๊ธฐ ์ „์— ๋จผ์ € ๋ชจ๋‹ˆํ„ฐ ๋ฝ์„ ํš๋“ํ•ฉ๋‹ˆ๋‹ค. ์ด๋•Œ ์Šค๋ ˆ๋“œ๋Š” "๋ชจ๋‹ˆํ„ฐ ์•ˆ์— ์žˆ๋‹ค"๊ณ  ๋งํ•ฉ๋‹ˆ๋‹ค. ๋ชจ๋‹ˆํ„ฐ ์•ˆ์— ์žˆ๋Š” ๋™์•ˆ ์Šค๋ ˆ๋“œ๋Š” ๋ณดํ˜ธ๋œ ๋ชจ๋“  ๋ฐ์ดํ„ฐ์— ๋Œ€ํ•œ ์ œ์–ด๊ถŒ์„ ๊ฐ€์ง€๋ฉฐ, ์ž์œ ๋กญ๊ฒŒ ๊ฒ€์‚ฌํ•˜๊ฑฐ๋‚˜ ์ˆ˜์ •ํ•  ์ˆ˜ ์žˆ์Šต๋‹ˆ๋‹ค. ๋ณดํ˜ธ๋œ ๋ฐ์ดํ„ฐ์— ๋Œ€ํ•œ ์ ‘๊ทผ์ด ์™„๋ฃŒ๋˜๋ฉด ๋ชจ๋‹ˆํ„ฐ ๋ฝ์„ ํ•ด์ œํ•ฉ๋‹ˆ๋‹ค.

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

๋ชจ๋‹ˆํ„ฐ์˜ ์ด๋ก ์ ์ธ ๊ธฐ๋ฐ˜์€ C.A.R.ํ˜ธ์–ด๊ฐ€ ๋งˆ๋ จํ–ˆ์Šต๋‹ˆ๋‹ค. ์‹ค์ œ์ ์ธ ์‚ฌ์šฉ๋ฒ•์€ ๋‚˜์ค‘์— Mesa ์šด์˜ ์ฒด์ œ์— ๊ด€ํ•œ ๋…ผ๋ฌธ์—์„œ ๋” ๋ฐœ์ „๋˜์—ˆ์Šต๋‹ˆ๋‹ค. ์กฐ๊ฑด ๋ณ€์ˆ˜์˜ ํƒ€์ž…๊ณผ ํ•จ์ˆ˜๋Š” include/threads/synch.h์— ์„ ์–ธ๋˜์–ด ์žˆ์Šต๋‹ˆ๋‹ค.

์กฐ๊ฑด ๋ณ€์ˆ˜๋ฅผ ๋‚˜ํƒ€๋ƒ…๋‹ˆ๋‹ค.

struct condition;

cond๋ฅผ ์ƒˆ๋กœ์šด ์กฐ๊ฑด ๋ณ€์ˆ˜๋กœ ์ดˆ๊ธฐํ™”ํ•ฉ๋‹ˆ๋‹ค.

void cond_init (struct condition *cond);

์›์ž์ ์œผ๋กœ lock(๋ชจ๋‹ˆํ„ฐ ๋ฝ)์„ ํ•ด์ œํ•˜๊ณ  ๋‹ค๋ฅธ ์ฝ”๋“œ์—์„œ cond(์กฐ๊ฑด ๋ณ€์ˆ˜)๊ฐ€ ์‹œ๊ทธ๋„์„ ๋ฐ›์„ ๋•Œ๊นŒ์ง€ ๋Œ€๊ธฐํ•ฉ๋‹ˆ๋‹ค. cond๊ฐ€ ์‹œ๊ทธ๋„์„ ๋ฐ›์€ ํ›„, ๋ฐ˜ํ™˜ํ•˜๊ธฐ ์ „์— ๋‹ค์‹œ lock์„ ์–ป์Šต๋‹ˆ๋‹ค. ์ด ํ•จ์ˆ˜๋ฅผ ํ˜ธ์ถœํ•˜๊ธฐ ์ „์— lock์„ ๋ณด์œ ํ•ด์•ผ ํ•ฉ๋‹ˆ๋‹ค. ์‹œ๊ทธ๋„์„ ๋ณด๋‚ด๊ณ  ๋Œ€๊ธฐ์—์„œ ๊นจ์–ด๋‚˜๋Š” ๊ฒƒ์€ ์›์ž์ ์ธ ์—ฐ์‚ฐ์ด ์•„๋‹™๋‹ˆ๋‹ค. ๋”ฐ๋ผ์„œ ์ผ๋ฐ˜์ ์œผ๋กœ cond_wait() ํ˜ธ์ถœ์ž๋Š” ๋Œ€๊ธฐ๊ฐ€ ์™„๋ฃŒ๋œ ํ›„ ์กฐ๊ฑด์„ ๋‹ค์‹œ ํ™•์ธํ•˜๊ณ  ํ•„์š”ํ•œ ๊ฒฝ์šฐ ๋‹ค์‹œ ๋Œ€๊ธฐํ•ด์•ผ ํ•ฉ๋‹ˆ๋‹ค. ์˜ˆ์ œ๋Š” ๋‹ค์Œ ์„น์…˜์—์„œ ์„ค๋ช…ํ•ฉ๋‹ˆ๋‹ค.

void cond_wait (struct condition *cond, struct lock *lock);

๋งŒ์•ฝ cond(๋ชจ๋‹ˆํ„ฐ ๋ฝ lock์œผ๋กœ ๋ณดํ˜ธ๋˜๋Š”)์— ๋Œ€๊ธฐ ์ค‘์ธ ์Šค๋ ˆ๋“œ๊ฐ€ ์žˆ๋‹ค๋ฉด, ์ด ํ•จ์ˆ˜๋Š” ๊ทธ ์ค‘ ํ•˜๋‚˜๋ฅผ ๊นจ์›๋‹ˆ๋‹ค. ๋Œ€๊ธฐ ์ค‘์ธ ์Šค๋ ˆ๋“œ๊ฐ€ ์—†๋‹ค๋ฉด ์–ด๋–ค ๋™์ž‘๋„ ์ˆ˜ํ–‰ํ•˜์ง€ ์•Š๊ณ  ๋ฐ˜ํ™˜ํ•ฉ๋‹ˆ๋‹ค. ์ด ํ•จ์ˆ˜๋ฅผ ํ˜ธ์ถœํ•˜๊ธฐ ์ „์— lock์„ ๋ณด์œ ํ•ด์•ผ ํ•ฉ๋‹ˆ๋‹ค.

void cond_signal (struct condition *cond, struct lock *lock);

cond(๋ชจ๋‹ˆํ„ฐ ๋ฝ lock์œผ๋กœ ๋ณดํ˜ธ๋˜๋Š”)์— ๋Œ€๊ธฐ ์ค‘์ธ ๋ชจ๋“  ์Šค๋ ˆ๋“œ(์žˆ๋Š” ๊ฒฝ์šฐ)๋ฅผ ๊นจ์›๋‹ˆ๋‹ค. ์ด ํ•จ์ˆ˜๋ฅผ ํ˜ธ์ถœํ•˜๊ธฐ ์ „์— lock์„ ๋ณด์œ ํ•ด์•ผ ํ•ฉ๋‹ˆ๋‹ค.

void cond_broadcast (struct condition *cond, struct lock *lock);

Monitor Example

๋ชจ๋‹ˆํ„ฐ์˜ ์ „ํ˜•์ ์ธ ์˜ˆ๋Š” ํ•˜๋‚˜ ์ด์ƒ์˜ "์ƒ์‚ฐ์ž" ์Šค๋ ˆ๋“œ๊ฐ€ ๋ฌธ์ž๋ฅผ ์ž‘์„ฑํ•˜๊ณ  ํ•˜๋‚˜ ์ด์ƒ์˜ "์†Œ๋น„์ž" ์Šค๋ ˆ๋“œ๊ฐ€ ๋ฌธ์ž๋ฅผ ์ฝ๋Š” ๋ฒ„ํผ ์ฒ˜๋ฆฌ์ž…๋‹ˆ๋‹ค. ์ด๋ฅผ ๊ตฌํ˜„ํ•˜๊ธฐ ์œ„ํ•ด์„œ๋Š” ๋ชจ๋‹ˆํ„ฐ ๋ฝ ์™ธ์—๋„ not_full๊ณผ not_empty๋ผ๊ณ  ๋ถ€๋ฅผ ๋‘ ๊ฐ€์ง€ ์กฐ๊ฑด ๋ณ€์ˆ˜๊ฐ€ ํ•„์š”ํ•ฉ๋‹ˆ๋‹ค.

char buf[BUF_SIZE];     /* Buffer. */
    size_t n = 0;         /* 0 <= n <= BUF SIZE: # of characters in buffer. */
    size_t head = 0;        /* buf index of next char to write (mod BUF SIZE). */
    size_t tail = 0;         /* buf index of next char to read (mod BUF SIZE). */
    struct lock lock;         /* Monitor lock. */
    struct condition not_empty; /* Signaled when the buffer is not empty. */
    struct condition not_full;     /* Signaled when the buffer is not full. */

    ...initialize the locks and condition variables...

    void put (char ch) {
      lock_acquire (&lock);
      while (n == BUF_SIZE)    /* Can't add to buf as long as it's full. */
        cond_wait (&not_full, &lock);
      buf[head++ % BUF_SIZE] = ch;    /* Add ch to buf. */
      n++;
      cond_signal (&not_empty, &lock);    /* buf can't be empty anymore. */
      lock_release (&lock);
    }

    char get (void) {
      char ch;
      lock_acquire (&lock);
      while (n == 0)        /* Can't read buf as long as it's empty. */
        cond_wait (&not_empty, &lock);
      ch = buf[tail++ % BUF_SIZE];    /* Get ch from buf. */
      n--;
      cond_signal (&not_full, &lock);    /* buf can't be full anymore. */
      lock_release (&lock);
    }

์œ„์˜ ์ฝ”๋“œ๊ฐ€ ์™„์ „ํžˆ ์ •ํ™•ํ•˜๋ ค๋ฉด BUF_SIZE๊ฐ€ SIZE_MAX + 1๋กœ ๋‚˜๋ˆ„์–ด ๋–จ์–ด์ ธ์•ผ ํ•จ์— ์œ ์˜ํ•˜์„ธ์š”. ๊ทธ๋ ‡์ง€ ์•Š์œผ๋ฉด head๊ฐ€ 0์œผ๋กœ ๋˜๋Œ์•„๊ฐˆ ๋•Œ ์ฒ˜์Œ์œผ๋กœ ์‹คํŒจํ•  ์ˆ˜ ์žˆ์Šต๋‹ˆ๋‹ค. ์‹ค์ œ๋กœ๋Š” BUF_SIZE๊ฐ€ ๋ณดํ†ต 2์˜ ๊ฑฐ๋“ญ์ œ๊ณฑ์ˆ˜๊ฐ€ ๋  ๊ฒƒ์ž…๋‹ˆ๋‹ค.

Optimization Barriers

์ตœ์ ํ™” ์žฅ๋ฒฝ(optimization barrier) ์€ ์ปดํŒŒ์ผ๋Ÿฌ๊ฐ€ ์žฅ๋ฒฝ์„ ํ†ต๊ณผํ•˜๋Š” ๋ฉ”๋ชจ๋ฆฌ ์ƒํƒœ์— ๋Œ€ํ•ด ๊ฐ€์ •์„ ํ•  ์ˆ˜ ์—†๋„๋ก ํ•˜๋Š” ํŠน๋ณ„ํ•œ ๋ฌธ์žฅ์ž…๋‹ˆ๋‹ค. ์ปดํŒŒ์ผ๋Ÿฌ๋Š” ์žฅ๋ฒฝ์„ ํ†ต๊ณผํ•˜๋Š” ๋ณ€์ˆ˜์˜ ์ฝ๊ธฐ ๋˜๋Š” ์“ฐ๊ธฐ๋ฅผ ์žฌ๋ฐฐ์—ดํ•˜์ง€ ์•Š๊ฑฐ๋‚˜, ๋ณ€์ˆ˜์˜ ๊ฐ’์ด ์žฅ๋ฒฝ์„ ํ†ต๊ณผํ•˜๋Š” ๋™์•ˆ ๋ณ€๊ฒฝ๋˜์ง€ ์•Š์•˜๋‹ค๊ณ  ๊ฐ€์ •ํ•˜์ง€ ์•Š์Šต๋‹ˆ๋‹ค. ๋‹ค๋งŒ, ์ฃผ์†Œ๊ฐ€ ์‚ฌ์šฉ๋˜์ง€ ์•Š๋Š” ๋กœ์ปฌ ๋ณ€์ˆ˜์— ๋Œ€ํ•ด์„œ๋Š” ์˜ˆ์™ธ์ž…๋‹ˆ๋‹ค. Pintos์—์„œ๋Š” include/threads/synch.h์—์„œ barrier() ๋งคํฌ๋กœ๋ฅผ ์ตœ์ ํ™” ์žฅ๋ฒฝ์œผ๋กœ ์ •์˜ํ•˜๊ณ  ์žˆ์Šต๋‹ˆ๋‹ค.

์ตœ์ ํ™” ์žฅ๋ฒฝ์„ ์‚ฌ์šฉํ•˜๋Š” ์ด์œ  ์ค‘ ํ•˜๋‚˜๋Š” ๋ฐ์ดํ„ฐ๊ฐ€ ๋น„๋™๊ธฐ์ ์œผ๋กœ ๋ณ€๊ฒฝ๋  ์ˆ˜ ์žˆ๋Š” ๊ฒฝ์šฐ์ž…๋‹ˆ๋‹ค. ๋‹ค๋ฅธ ์Šค๋ ˆ๋“œ๋‚˜ ์ธํ„ฐ๋ŸฝํŠธ ํ•ธ๋“ค๋Ÿฌ์™€ ๊ฐ™์€ ์š”์†Œ์— ์˜ํ•ด ์ปดํŒŒ์ผ๋Ÿฌ์˜ ์•Œ์ง€ ๋ชปํ•˜๋Š” ์ƒํ™ฉ์—์„œ ๋ฐ์ดํ„ฐ๊ฐ€ ๋ณ€๊ฒฝ๋  ์ˆ˜ ์žˆ์Šต๋‹ˆ๋‹ค. devices/timer.c์˜ too_many_loops() ํ•จ์ˆ˜๊ฐ€ ์ด๋ฅผ ์˜ˆ๋กœ ๋“ค ์ˆ˜ ์žˆ์Šต๋‹ˆ๋‹ค. ์ด ํ•จ์ˆ˜๋Š” ํƒ€์ด๋จธ ํ‹ฑ์ด ๋ฐœ์ƒํ•  ๋•Œ๊นŒ์ง€ ๋ฃจํ”„๋ฅผ ๋Œ๋ฉด์„œ busy-waiting์œผ๋กœ ์‹œ์ž‘๋ฉ๋‹ˆ๋‹ค.

    /* Wait for a timer tick. */
    int64_t start = ticks;
    while (ticks == start)
        barrier();

๋ฃจํ”„์—์„œ ์ตœ์ ํ™” ์žฅ๋ฒฝ์ด ์—†๋Š” ๊ฒฝ์šฐ, ์ปดํŒŒ์ผ๋Ÿฌ๋Š” start์™€ ticks๊ฐ€ ์ฒ˜์Œ์— ๋™์ผํ•˜๋ฉฐ ๋ฃจํ”„ ์ž์ฒด์—์„œ ๋ณ€๊ฒฝ๋˜์ง€ ์•Š๊ธฐ ๋•Œ๋ฌธ์— ๋ฃจํ”„๊ฐ€ ์ข…๋ฃŒ๋˜์ง€ ์•Š์„ ๊ฒƒ์ด๋ผ๊ณ  ๊ฒฐ๋ก ์„ ๋‚ด๋ฆด ์ˆ˜ ์žˆ์Šต๋‹ˆ๋‹ค. ๊ทธ๋Ÿฌ๋ฉด ์ปดํŒŒ์ผ๋Ÿฌ๋Š” ํ•จ์ˆ˜๋ฅผ ๋ฌดํ•œ ๋ฃจํ”„๋กœ "์ตœ์ ํ™”"ํ•  ์ˆ˜ ์žˆ์œผ๋ฉฐ, ์ด๋Š” ๋ถ„๋ช…ํžˆ ์›ํ•˜์ง€ ์•Š๋Š” ๊ฒฐ๊ณผ์ž…๋‹ˆ๋‹ค.

์ตœ์ ํ™” ์žฅ๋ฒฝ์€ ๋‹ค๋ฅธ ์ปดํŒŒ์ผ๋Ÿฌ ์ตœ์ ํ™”๋ฅผ ํ”ผํ•˜๊ธฐ ์œ„ํ•ด ์‚ฌ์šฉ๋  ์ˆ˜๋„ ์žˆ์Šต๋‹ˆ๋‹ค. devices/timer.c์— ์žˆ๋Š” busy_wait() ํ•จ์ˆ˜๊ฐ€ ์ด๋ฅผ ์˜ˆ๋กœ ๋“ค ์ˆ˜ ์žˆ์Šต๋‹ˆ๋‹ค. ์ด ํ•จ์ˆ˜์—๋Š” ๋‹ค์Œ๊ณผ ๊ฐ™์€ ๋ฃจํ”„๊ฐ€ ํฌํ•จ๋˜์–ด ์žˆ์Šต๋‹ˆ๋‹ค.

    while (loops-- > 0)
      barrier ();

์ด ๋ฃจํ”„์˜ ๋ชฉํ‘œ๋Š” ์›๋ž˜ ๊ฐ’๋ถ€ํ„ฐ 0๊นŒ์ง€ ๋ฃจํ”„๋ฅผ ์นด์šดํŠธํ•˜์—ฌ ๋ฐ”์œ ๋Œ€๊ธฐ(busy-wait)๋ฅผ ์ˆ˜ํ–‰ํ•˜๋Š” ๊ฒƒ์ž…๋‹ˆ๋‹ค. ์ตœ์ ํ™” ์žฅ๋ฒฝ์ด ์—†๋Š” ๊ฒฝ์šฐ ์ปดํŒŒ์ผ๋Ÿฌ๋Š” ์œ ์šฉํ•œ ์ถœ๋ ฅ์„ ์ƒ์„ฑํ•˜์ง€ ์•Š์œผ๋ฉฐ ๋ถ€์ž‘์šฉ๋„ ์—†๊ธฐ ๋•Œ๋ฌธ์— ๋ฃจํ”„๋ฅผ ์™„์ „ํžˆ ์‚ญ์ œํ•  ์ˆ˜ ์žˆ์Šต๋‹ˆ๋‹ค. ์žฅ๋ฒฝ์€ ์ปดํŒŒ์ผ๋Ÿฌ์—๊ฒŒ ๋ฃจํ”„ ๋ณธ๋ฌธ์ด ์ค‘์š”ํ•œ ํšจ๊ณผ๊ฐ€ ์žˆ๋‹ค๊ณ  ๊ฐ€์ •ํ•˜๋„๋ก ๊ฐ•์ œํ•ฉ๋‹ˆ๋‹ค.

๋งˆ์ง€๋ง‰์œผ๋กœ, ์ตœ์ ํ™” ์žฅ๋ฒฝ์€ ๋ฉ”๋ชจ๋ฆฌ ์ฝ๊ธฐ ๋˜๋Š” ์“ฐ๊ธฐ์˜ ์ˆœ์„œ๋ฅผ ๊ฐ•์ œํ•˜๊ธฐ ์œ„ํ•ด ์‚ฌ์šฉ๋  ์ˆ˜๋„ ์žˆ์Šต๋‹ˆ๋‹ค. ์˜ˆ๋ฅผ ๋“ค์–ด, ํƒ€์ด๋จธ ์ธํ„ฐ๋ŸฝํŠธ๊ฐ€ ๋ฐœ์ƒํ•  ๋•Œ๋งˆ๋‹ค ๊ธ€๋กœ๋ฒŒ ๋ณ€์ˆ˜ timer_put_char์— ์ €์žฅ๋œ ๋ฌธ์ž๋ฅผ ์ฝ˜์†”์— ์ถœ๋ ฅํ•˜๋Š” "๊ธฐ๋Šฅ"์„ ์ถ”๊ฐ€ํ•œ๋‹ค๊ณ  ๊ฐ€์ •ํ•ด๋ณด๊ฒ ์Šต๋‹ˆ๋‹ค. ๋‹จ, ๊ธ€๋กœ๋ฒŒ ๋ถ€์šธ ๋ณ€์ˆ˜ timer_do_put์ด true์ธ ๊ฒฝ์šฐ์—๋งŒ ์ถœ๋ ฅํ•ด์•ผ ํ•ฉ๋‹ˆ๋‹ค. ์ด ๊ฒฝ์šฐ x๋ฅผ ์ถœ๋ ฅํ•˜๊ธฐ ์œ„ํ•ด ์ตœ์ ํ™” ์žฅ๋ฒฝ์„ ์‚ฌ์šฉํ•˜๋Š” ๊ฒƒ์ด ๊ฐ€์žฅ ์ข‹์Šต๋‹ˆ๋‹ค.

    timer_put_char = 'x';
    barrier ();
    timer_do_put = true;

์žฅ๋ฒฝ์ด ์—†์œผ๋ฉด ์ปดํŒŒ์ผ๋Ÿฌ๋Š” ์—ฐ์‚ฐ์„ ์žฌ๋ฐฐ์—ดํ•  ์ž์œ ๊ฐ€ ์žˆ๊ธฐ ๋•Œ๋ฌธ์— ์ฝ”๋“œ์— ๋ฒ„๊ทธ๊ฐ€ ์žˆ์„ ์ˆ˜ ์žˆ์Šต๋‹ˆ๋‹ค. ์ปดํŒŒ์ผ๋Ÿฌ๋Š” ์—ฐ์‚ฐ์˜ ์ˆœ์„œ๋ฅผ ์œ ์ง€ํ•  ์ด์œ ๊ฐ€ ์—†๋‹ค๊ณ  ํŒ๋‹จํ•˜๋ฉด ์—ฐ์‚ฐ์˜ ์ˆœ์„œ๋ฅผ ๋ฐ”๊ฟ€ ์ˆ˜ ์žˆ์Šต๋‹ˆ๋‹ค. ์ด ๊ฒฝ์šฐ, ์ปดํŒŒ์ผ๋Ÿฌ๋Š” ํ• ๋‹น๋ฌธ์˜ ์ˆœ์„œ๊ฐ€ ์ค‘์š”ํ•˜๋‹ค๋Š” ๊ฒƒ์„ ์•Œ์ง€ ๋ชปํ•˜๊ธฐ ๋•Œ๋ฌธ์— ์ตœ์ ํ™” ๊ธฐ๋Šฅ์ด ํ• ๋‹น๋ฌธ์˜ ์ˆœ์„œ๋ฅผ ๋ฐ”๊ฟ€ ์ˆ˜ ์žˆ์Šต๋‹ˆ๋‹ค. ์‹ค์ œ๋กœ ์ด๋ ‡๊ฒŒ ํ• ์ง€๋Š” ์•Œ ์ˆ˜ ์—†์œผ๋ฉฐ, ์ปดํŒŒ์ผ๋Ÿฌ์—๊ฒŒ ๋‹ค๋ฅธ ์ตœ์ ํ™” ํ”Œ๋ž˜๊ทธ๋ฅผ ์ „๋‹ฌํ•˜๊ฑฐ๋‚˜ ๋‹ค๋ฅธ ๋ฒ„์ „์˜ ์ปดํŒŒ์ผ๋Ÿฌ๋ฅผ ์‚ฌ์šฉํ•˜๋ฉด ๋‹ค๋ฅธ ๋™์ž‘์ด ๋ฐœ์ƒํ•  ์ˆ˜ ์žˆ์Šต๋‹ˆ๋‹ค.

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

    enum intr_level old_level = intr_disable ();
    timer_put_char = 'x';
    timer_do_put = true;
    intr_set_level (old_level);

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

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

    lock_acquire (&timer_lock);        /* INCORRECT CODE */
    timer_put_char = 'x';
    timer_do_put = true;
    lock_release (&timer_lock);

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

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


โŒจ๏ธ ์ฝ”๋“œ ๊ตฌํ˜„ โŒจ๏ธ

thread๊ฐ€ priority์— ๋”ฐ๋ผ ์‹คํ–‰์ด ๋˜๋„๋ก ๊ตฌํ˜„ํ•˜๋ ค๋ฉด '์งˆ์„œ'๋ฅผ ๋งŒ๋“ค์–ด์•ผํ•œ๋‹ค. pintOS์—์„œ๋Š” ์ด๋ฅผ lock&semaphore๋กœ ๊ตฌํ˜„ํ•œ๋‹ค. ์•ž์„œ gitbook์— ๋‚˜์™€์žˆ๋“ฏ์ด pintOS์—์„œ๋Š” lock๋ฅผ semaphore 1๋กœ ๊ตฌํ˜„ํ•œ๋‹ค. ํ•˜์ง€๋งŒ lock๊ณผ semaphore์˜ ์ฐจ์ด์ ์€ lock์„ ๊ฐ€์ง€๊ณ  ์žˆ๋Š” thread๊ฐ€ lock์„ ๋†“์•„์ค„ ์ˆ˜ ์žˆ๋‹ค๋Š” ๊ฒƒ์ด๋‹ค.

์ฝ”๋“œ๋กœ ๊ตฌํ˜„ํ•˜๊ธฐ ์œ„ํ•ด ๋จผ์ € sema_init()์ฝ”๋“œ๋ฅผ ํ™•์ธํ•ด๋ณด์ž.

//thread/synch.c

void sema_init(struct semaphore *sema, unsigned value)
{
	ASSERT(sema != NULL);
	sema->value = value;
	list_init(&sema->waiters);
}

assert๋ฅผ ํ†ตํ•ด ์„ธ๋งˆํฌ์–ด๊ฐ€ null์ด ์•„๋‹Œ์ง€ ํ™•์ธํ•˜๊ณ , ์„ธ๋งˆํฌ์–ด ๊ตฌ์กฐ์ฒด์˜ value์— ์ฃผ์–ด์ง„ ์ธ์ž ๊ฐ’์„ ์ดˆ๊ธฐ๊ฐ’์œผ๋กœ ํ• ๋‹นํ•œ๋‹ค.
์ดํ›„ ์„ธ๋งˆํฌ์–ด ๊ตฌ์กฐ์ฒด ๋‚ด๋ถ€์˜ waiters๋ฆฌ์ŠคํŠธ๋ฅผ list_init()ํ•จ์ˆ˜๋ฅผ ์‚ฌ์šฉํ•ด ์ดˆ๊ธฐํ™” ํ•œ๋‹ค.


sema_down()์„ ์ˆ˜์ •ํ•ด์ฃผ์ž.

๊ธฐ์กด์— ์žˆ๋˜ sema_down()์€ ์•„๋ž˜์™€ ๊ฐ™๋‹ค.

//thread/synch.c

/* Down or "P" operation on a semaphore.  Waits for SEMA's value
   to become positive and then atomically decrements it.

   This function may sleep, so it must not be called within an
   interrupt handler.  This function may be called with
   interrupts disabled, but if it sleeps then the next scheduled
   thread will probably turn interrupts back on. This is
   sema_down function. */
void
sema_down (struct semaphore *sema) {
	enum intr_level old_level;

	ASSERT (sema != NULL);
	ASSERT (!intr_context ());

	old_level = intr_disable ();
	while (sema->value == 0) {
		list_push_back (&sema->waiters, &thread_current ()->elem);
		thread_block ();
	}
	sema->value--;
	intr_set_level (old_level);
}

intr_disable ํ•จ์ˆ˜๋ฅผ ํ˜ธ์ถœํ•˜์—ฌ ํ˜„์žฌ ์ธํ„ฐ๋ŸฝํŠธ ๋ ˆ๋ฒจ์„ ์ €์žฅํ•˜๊ณ  ์ธํ„ฐ๋ŸฝํŠธ๋ฅผ ๋น„ํ™œ์„ฑํ•œ ๋’ค, while ๋ฃจํ”„๋ฅผ ์‚ฌ์šฉํ•˜์—ฌ ์„ธ๋งˆํฌ์–ด์˜ ๊ฐ’์ด 0์ธ ๋™์•ˆ ๋Œ€๊ธฐํ•œ๋‹ค.
while ๋ฃจํ”„๋ฅผ ๋น ์ ธ๋‚˜์˜ค๋ฉด ์„ธ๋งˆํฌ์–ด์˜ ๊ฐ’์„ 1 ๊ฐ์†Œ์‹œํ‚จ๋‹ค. ์ดํ›„ intr_set_level ํ•จ์ˆ˜๋ฅผ ํ˜ธ์ถœํ•˜์—ฌ ์ด์ „ ์ธํ„ฐ๋ŸฝํŠธ ๋ ˆ๋ฒจ์„ ๋ณต์›ํ•˜๊ณ  ์ธํ„ฐ๋ŸฝํŠธ๋ฅผ ๋‹ค์‹œ ํ™œ์„ฑํ™”ํ•œ๋‹ค.

์ด๋ง์„ ์ •๋ฆฌํ•ด๋ณด๋ฉด, threadA๋Š” ์„ธ๋งˆํฌ์–ด๊ฐ€ 0์ธ ๋™์•ˆ ๋ธ”๋ก๋˜๊ณ  ๋Œ€๊ธฐ์ƒํƒœ์— ์žˆ๋‹ค๊ฐ€ running์ƒํƒœ์— ์žˆ๋Š” ๋‹ค๋ฅธ thread๊ฐ€ ํ•ด๋‹น ์„ธ๋งˆํฌ์–ด๋ฅผ 1๋กœ ์˜ฌ๋ ค์ฃผ๋ฉด ๊ธฐ๋‹ค๋ฆฌ๊ณ  ์žˆ๋˜ threadA๊ฐ€ while๋ฌธ์„ ๋น ์ ธ๋‚˜์˜ค๊ณ  threadA๊ฐ€ ์„ธ๋งˆํฌ์–ด๋ฅผ ๊ฐ€์ ธ๊ฐ”๋‹ค๋Š” ๋œป์œผ๋กœ 0์œผ๋กœ(sema->value--;) ๋งŒ๋“ค์–ด์ฃผ๋Š” ๊ฒƒ์ด๋‹ค. ์ด๋ฅผ ํ†ตํ•ด ๋‹ค๋ฅธ ์Šค๋ ˆ๋“œ๊ฐ€ ๋™์‹œ์— ์ ‘๊ทผํ•˜์ง€ ๋ชปํ•˜๋„๋ก ํ•œ๋‹ค.

์šฐ๋ฆฌํŒ€ ์ˆ˜์ • ์ฝ”๋“œ ๐Ÿค“

//thread/synch.c

void sema_down(struct semaphore *sema)
{
	enum intr_level old_level;

	ASSERT(sema != NULL);
	ASSERT(!intr_context());

	old_level = intr_disable();
	while (sema->value == 0) /* sema์— ์ ‘๊ทผํ•  ์ˆ˜ ์—†์„ ๋•Œ */
	{
		list_insert_ordered(&sema->waiters, &thread_current()->elem, &priority_less, NULL); /* ์ ‘๊ทผ ๊ถŒํ•œ์ด ์ƒ๊ธฐ๊ธฐ๋ฅผ ๊ธฐ๋‹ค๋ฆฌ๋Š” ์Šค๋ ˆ๋“œ๋ฅผ waiters์— ์ถ”๊ฐ€ */
		thread_block();																		   /* ํ•ด๋‹น ์Šค๋ ˆ๋“œ block */
	}
	sema->value--;
	intr_set_level(old_level);
}

waiters list์— ๋“ค์–ด๊ฐˆ ๋•Œ, priority ์ˆœ์œผ๋กœ ์ •๋ ฌ๋˜์–ด ๋„ฃ์–ด์ ธ์„œ priority์— ๋”ฐ๋ผ ready_list๊ฐ€ ์ •๋ ฌ๋  ์ˆ˜ ์žˆ๋„๋ก ์ˆ˜์ •ํ–ˆ๋‹ค.


sema_up()์„ ์ˆ˜์ •ํ•ด์ฃผ์ž.

๊ธฐ์กด์— ์žˆ๋˜ sema_up()์€ ์•„๋ž˜์™€ ๊ฐ™๋‹ค.

//thread/synch.c

/* Up or "V" operation on a semaphore.  Increments SEMA's value
   and wakes up one thread of those waiting for SEMA, if any.

   This function may be called from an interrupt handler. */
void
sema_up (struct semaphore *sema) {
	enum intr_level old_level;

	ASSERT (sema != NULL);

	old_level = intr_disable ();
	if (!list_empty (&sema->waiters))
		thread_unblock (list_entry (list_pop_front (&sema->waiters),
					struct thread, elem));
	sema->value++;
	intr_set_level (old_level);
}

์ธํ„ฐ๋ŸฝํŠธ ๋น„ํ™œ์„ฑํ™”๋ฅผ ํ†ตํ•ด ํ˜„์žฌ ์‹คํ–‰ ์ค‘์ธ ์ฝ”๋“œ๊ฐ€ ์ค‘๋‹จ๋˜์ง€ ์•Š๋„๋ก ํ•œ๋‹ค. ์„ธ๋งˆํฌ์–ด์˜ ๋Œ€๊ธฐ ๋ฆฌ์ŠคํŠธ์— ๋Œ€๊ธฐ ์ค‘์ธ ์Šค๋ ˆ๋“œ๊ฐ€ ์žˆ๋Š”์ง€ ํ™•์ธํ•˜๊ณ , ๋Œ€๊ธฐ์ค‘์ธ ์Šค๋ ˆ๋“œ๊ฐ€ ์žˆ๋‹ค๋ฉด list_pop_front ํ•จ์ˆ˜๋ฅผ ์‚ฌ์šฉํ•˜์—ฌ ์ฒซ ๋ฒˆ์งธ ์Šค๋ ˆ๋“œ๋ฅผ ๊บผ๋‚ด๊ณ , ์ด ์Šค๋ ˆ๋“œ๋ฅผ thread_unblock ํ•จ์ˆ˜๋ฅผ ํ˜ธ์ถœํ•˜์—ฌ ์ค€๋น„ ์ƒํƒœ๋กœ ๋ณ€๊ฒฝํ•œ๋‹ค. ์ด๋ฅผ ํ†ตํ•ด ์„ธ๋งˆํฌ์–ด๋ฅผ ๊ธฐ๋‹ค๋ฆฌ๊ณ  ์žˆ๋˜ ์Šค๋ ˆ๋“œ๊ฐ€ ์‹คํ–‰ ๊ฐ€๋Šฅํ•œ ์ƒํƒœ๋กœ ์ „ํ™˜ํ•œ๋‹ค.

์„ธ๋งˆํฌ์–ด์˜ ๊ฐ’์„ 1 ์ฆ๊ฐ€์‹œํ‚ด์œผ๋กœ์จ ํ˜„์žฌ running์ƒํƒœ์— ์žˆ๋Š” thread๋Š” ํ•ด๋‹น ์„ธ๋งˆํฌ์–ด๊ฐ€ ์ง€ํ‚ค๊ณ  ์žˆ๋Š” ์ž์›์„ ๋‹ค์ผ์Œ์„ ์•Œ๋ฆฌ๊ณ , waiters list์˜ head์— ์žˆ๋Š” thread๊ฐ€ ํ•ด๋‹น์ž์›์— ์ ‘๊ทผ ๊ฐ€๋Šฅํ•˜๋„๋ก ํ•œ๋‹ค.
๋งˆ์ง€๋ง‰์œผ๋กœ, ์ด์ „์˜ ์ธํ„ฐ๋ŸฝํŠธ ๋ ˆ๋ฒจ์„ ๋ณต์›ํ•˜๊ณ  ์ธํ„ฐ๋ŸฝํŠธ๋ฅผ ๋‹ค์‹œ ํ™œ์„ฑํ™”ํ•œ๋‹ค.

์šฐ๋ฆฌํŒ€ ์ˆ˜์ • ์ฝ”๋“œ ๐Ÿค“

//thread/synch.c

void sema_up(struct semaphore *sema)
{
	enum intr_level old_level;

	ASSERT(sema != NULL);

	old_level = intr_disable();
	if (!list_empty(&sema->waiters))
	{
		list_sort(&sema->waiters, &priority_less, NULL); /* ์šฐ์„  ์ˆœ์œ„๊ฐ€ ๋ณ€๊ฒฝ๋์„ ๊ฒฝ์šฐ waiters ์ •๋ ฌ */
		thread_unblock(list_entry(list_pop_front(&sema->waiters),
								  struct thread, elem)); /* prioirty๊ฐ€ ๊ฐ€์žฅ ๋†’์€ ์Šค๋ ˆ๋“œ๋ฅผ unblock */
	}
	sema->value++;
	test_max_priority();
	intr_set_level(old_level);
}

waiters๋ฆฌ์ŠคํŠธ์— ์žˆ๋Š” head๋ฅผ ๋ฝ‘์•„์˜ฌ๋•Œ priority์— ๋”ฐ๋ผ ํ•œ๋ฒˆ ๋” ์ •๋ ฌ์‹œํ‚ค๊ณ  ๋ฝ‘์•„์˜ด์œผ๋กœ์จ priority์— ๋”ฐ๋ผ ๊ตฌํ˜„๋  ์ˆ˜ ์žˆ๋„๋ก ์ˆ˜์ •ํ–ˆ๋‹ค.
์ดํ›„, ํ˜„์žฌ ์‹คํ–‰ ์ค‘์ธ ์Šค๋ ˆ๋“œ์˜ ์šฐ์„ ์ˆœ์œ„๋ณด๋‹ค ๋†’์€ ์šฐ์„ ์ˆœ์œ„๋ฅผ ๊ฐ€์ง„ ์Šค๋ ˆ๋“œ๊ฐ€ ์ค€๋น„ ๋ฆฌ์ŠคํŠธ์— ์žˆ๋Š” ๊ฒฝ์šฐ์—๋งŒ ํ˜„์žฌ ์Šค๋ ˆ๋“œ๋ฅผ ์–‘๋ณดํ•˜๋Š”test_max_priority()ํ•จ์ˆ˜๋ฅผ ์ถ”๊ฐ€ํ•จ์œผ๋กœ์จ prioirty๊ฐ€ ๊ฐ€์žฅ ๋†’์€ ์Šค๋ ˆ๋“œ๊ฐ€ running thread๊ฐ€ ๋˜๋„๋ก ๊ตฌํ˜„ํ•œ๋‹ค.


cond_wait()์„ ์ˆ˜์ •ํ•ด๋ณด์ž.

//threads/thread.c

/* Atomically releases LOCK and waits for COND to be signaled by
   some other piece of code.  After COND is signaled, LOCK is
   reacquired before returning.  LOCK must be held before calling
   this function.

   The monitor implemented by this function is "Mesa" style, not
   "Hoare" style, that is, sending and receiving a signal are not
   an atomic operation.  Thus, typically the caller must recheck
   the condition after the wait completes and, if necessary, wait
   again.

   A given condition variable is associated with only a single
   lock, but one lock may be associated with any number of
   condition variables.  That is, there is a one-to-many mapping
   from locks to condition variables.

   This function may sleep, so it must not be called within an
   interrupt handler.  This function may be called with
   interrupts disabled, but interrupts will be turned back on if
   we need to sleep. */

cont_wait์— ๋‹ฌ๋ ค์žˆ๋Š” ์ฃผ์„์„ ํ•ด์„ํ•ด๋ณด๋ฉด ๋‹ค์Œ๊ณผ ๊ฐ™๋‹ค.

LOCK์„ ์›์ž์ ์œผ๋กœ ํ•ด์ œํ•˜๊ณ  COND๊ฐ€ ๋‹ค๋ฅธ ์ฝ”๋“œ์— ์˜ํ•ด ์‹œ๊ทธ๋„๋˜๊ธฐ๋ฅผ ๊ธฐ๋‹ค๋ฆฝ๋‹ˆ๋‹ค. COND๊ฐ€ ์‹œ๊ทธ๋„๋˜๋ฉด ๋ฐ˜ํ™˜ํ•˜๊ธฐ ์ „์— LOCK์„ ๋‹ค์‹œ ํš๋“ํ•ฉ๋‹ˆ๋‹ค. ์ด ํ•จ์ˆ˜๋ฅผ ํ˜ธ์ถœํ•˜๊ธฐ ์ „์— LOCK์„ ๋ณด์œ ํ•ด์•ผ ํ•ฉ๋‹ˆ๋‹ค.
์ด ํ•จ์ˆ˜๋กœ ๊ตฌํ˜„๋œ ๋ชจ๋‹ˆํ„ฐ๋Š” "Mesa" ์Šคํƒ€์ผ ์ด๋ฉฐ "Hoare" ์Šคํƒ€์ผ์ด ์•„๋‹™๋‹ˆ๋‹ค. ๋”ฐ๋ผ์„œ ๋ณดํ†ต ํ˜ธ์ถœ์ž๋Š” ๋Œ€๊ธฐ๊ฐ€ ์™„๋ฃŒ๋œ ํ›„ ์กฐ๊ฑด์„ ๋‹ค์‹œ ํ™•์ธํ•˜๊ณ  ํ•„์š”ํ•œ ๊ฒฝ์šฐ ๋‹ค์‹œ ๋Œ€๊ธฐํ•ด์•ผ ํ•ฉ๋‹ˆ๋‹ค.
ํŠน์ • ์กฐ๊ฑด ๋ณ€์ˆ˜๋Š” ํ•˜๋‚˜์˜ ๋ฝ์—๋งŒ ์—ฐ๊ฒฐ๋˜์ง€๋งŒ, ํ•˜๋‚˜์˜ ๋ฝ์€ ์—ฌ๋Ÿฌ ์กฐ๊ฑด ๋ณ€์ˆ˜์— ์—ฐ๊ฒฐ๋  ์ˆ˜ ์žˆ์Šต๋‹ˆ๋‹ค. ์ฆ‰, ๋ฝ์—์„œ ์กฐ๊ฑด ๋ณ€์ˆ˜๋กœ์˜ ์ผ๋Œ€๋‹ค ๋งคํ•‘์ด ์žˆ์Šต๋‹ˆ๋‹ค.
์ด ํ•จ์ˆ˜๋Š” sleep์ด ๋ฐœ์ƒํ•  ์ˆ˜ ์žˆ์œผ๋ฏ€๋กœ ์ธํ„ฐ๋ŸฝํŠธ ํ•ธ๋“ค๋Ÿฌ ๋‚ด์—์„œ ํ˜ธ์ถœํ•ด์„œ๋Š” ์•ˆ๋ฉ๋‹ˆ๋‹ค. ์ธํ„ฐ๋ŸฝํŠธ๊ฐ€ ๋น„ํ™œ์„ฑํ™”๋œ ์ƒํƒœ์—์„œ ํ˜ธ์ถœ๋˜๋”๋ผ๋„, sleep์ด ํ•„์š”ํ•œ ๊ฒฝ์šฐ ์ธํ„ฐ๋ŸฝํŠธ๊ฐ€ ๋‹ค์‹œ ํ™œ์„ฑํ™”๋ฉ๋‹ˆ๋‹ค.

์ฃผ์„์—์„œ ์–ธ๊ธ‰๋œ mesa ์Šคํƒ€์ผ๊ณผ hoare์Šคํƒ€์ผ์— ๋Œ€ํ•ด ์•Œ์•„๋ณด์ž.

Mesa ์Šคํƒ€์ผ:

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

Hoare ์Šคํƒ€์ผ:

  • ์‹ ํ˜ธ(signal)์™€ ๋Œ€๊ธฐ(wait) ์—ฐ์‚ฐ์ด ์›์ž์ ์ž…๋‹ˆ๋‹ค. ์ฆ‰, ์‹ ํ˜ธ๋ฅผ ๋ณด๋‚ธ ์Šค๋ ˆ๋“œ๋Š” ๋Œ€๊ธฐ ์ค‘์ธ ์Šค๋ ˆ๋“œ๋ฅผ ๊นจ์šฐ๊ณ , ๋Œ€๊ธฐ ์ค‘์ธ ์Šค๋ ˆ๋“œ๋Š” ์‹ ํ˜ธ๋ฅผ ๋ฐ›์„ ๋•Œ๊นŒ์ง€ ๋Œ€๊ธฐํ•ฉ๋‹ˆ๋‹ค.
  • ๋Œ€๊ธฐ ์ค‘์ธ ์Šค๋ ˆ๋“œ๊ฐ€ ๊นจ์–ด๋‚œ ํ›„์—๋Š” ์กฐ๊ฑด์ด ์ถฉ์กฑ๋˜์—ˆ์Œ์„ ๊ฐ€์ •ํ•  ์ˆ˜ ์žˆ์Šต๋‹ˆ๋‹ค. ๋”ฐ๋ผ์„œ ์กฐ๊ฑด์„ ํ™•์ธํ•  ํ•„์š” ์—†์ด ์ง„ํ–‰ํ•  ์ˆ˜ ์žˆ์Šต๋‹ˆ๋‹ค.

๋Œ€๊ธฐ ์ค‘์ธ ์Šค๋ ˆ๋“œ๊ฐ€ ๊นจ์–ด๋‚œ ํ›„์—๋Š” ๋‹ค์‹œ ์กฐ๊ฑด์„ ํ™•์ธํ•ด์•„ ํ•˜๋Š” ๊ฒƒ์„ ์—ผ๋‘ํ•ด๋‘๊ณ , ์ด๋ฒˆ์—๋Š” ๊ธฐ์กด ์ฝ”๋“œ์— ๋Œ€ํ•ด ์•Œ์•„๋ณด์ž.

//thread/synch.c

void
cond_wait (struct condition *cond, struct lock *lock) {
	struct semaphore_elem waiter;

	ASSERT (cond != NULL);
	ASSERT (lock != NULL);
	ASSERT (!intr_context ());
	ASSERT (lock_held_by_current_thread (lock));

	sema_init (&waiter.semaphore, 0);
	list_push_back (&cond->waiters, &waiter.elem);
	lock_release (lock);
	sema_down (&waiter.semaphore);
	lock_acquire (lock);
}

cond_wait ํ•จ์ˆ˜๋Š” ๋ชจ๋‹ˆํ„ฐ์•ˆ์˜ ์ฝ”๋“œ๊ฐ€ ํŠน์ • ์กฐ๊ฑด์ด ์ฐธ์ด ๋˜๊ธฐ๋ฅผ ๊ธฐ๋‹ค๋ฆด ๋•Œ, ๊ทธ ์ฝ”๋“œ๋Š” ์›ํ•˜๋Š” ์กฐ๊ฑด๊ณผ ๊ด€๋ จ๋œ ์ปจ๋””์…˜ ๋ณ€์ˆ˜๋ฅผ ๊ธฐ๋‹ค๋ฆฌ๋Š” ํ•จ์ˆ˜๋‹ค.(gitbook์ฐธ๊ณ )

gtibook์—์„œ๋Š” "์ƒ์‚ฐ์ž" ์Šค๋ ˆ๋“œ๊ฐ€ ๋ฌธ์ž๋ฅผ ์ž‘์„ฑํ•˜๊ณ  ํ•˜๋‚˜ ์ด์ƒ์˜ "์†Œ๋น„์ž" ์Šค๋ ˆ๋“œ๊ฐ€ ๋ฌธ์ž๋ฅผ ์ฝ๋Š” ๋ฒ„ํผ ์ฒ˜๋ฆฌ๋ฅผ ์˜ˆ์‹œ๋กœ ๋“ค๊ณ ์žˆ๋Š”๋ฐ, ํ•œ '์ƒ์‚ฐ์ž'์Šค๋ ˆ๋“œ๋Š” ํ•ด๋‹น list(waiters)๊ฐ€ ๋น„์—ˆ์œผ๋ฉด buffer๋ฅผ ๊ณ„์† ์Œ“๊ณ , '์†Œ๋น„์ž' ์Šค๋ ˆ๋“œ๋Š” ๋ฒ„ํผ๊ฐ€ list(waiters)์— ์Œ“์ด๋ฉด buffer๋ฅผ ๋น„์–ด๋‚ด๋„๋ก ํ•˜๋Š” ๋ฐฉ๋ฒ•์ด๋‹ค.

struct condition
{
	struct list waiters; /* List of waiting threads. */
};

struct condtion์„ ๋ณด๋ฉด ํ•ด๋‹น list๋ฅผ ์„ ์–ธํ•˜๋„๋ก ๋˜์–ด์žˆ๋‹ค. ๊ธฐ์กด ์ฝ”๋“œ์—์„œ๋Š” ๋Œ€๊ธฐ ์Šค๋ ˆ๋“œ์˜ semaphore_elem์ด waiters ๋ฆฌ์ŠคํŠธ์— ๋’ค์ชฝ์— ์ถ”๊ฐ€๋˜๋Š” ๋ฐฉ์‹์ด๋‹ค. ์ด๋ฅผ ์šฐ์„ ์ˆœ์œ„๋กœ ์ •๋ ฌ๋œ ์œ„์น˜์— ์‚ฝ์ž…๋˜๋„๋ก ๋ณ€๊ฒฝํ•˜์ž. ๊ทธ๋ฆฌ๊ณ  ๋Œ€๊ธฐ ์Šค๋ ˆ๋“œ์˜ semaphore_elem์— ์Šค๋ ˆ๋“œ์˜ ์šฐ์„ ์ˆœ์œ„๋ฅผ ์ €์žฅํ•˜๋„๋ก ์ถ”๊ฐ€ํ•˜์ž.

์šฐ๋ฆฌํŒ€ ์ˆ˜์ • ์ฝ”๋“œ ๐Ÿค“

//thread/synch.c

void cond_wait(struct condition *cond, struct lock *lock)
{
	struct semaphore_elem waiter;

	ASSERT(cond != NULL);
	ASSERT(lock != NULL);
	ASSERT(!intr_context());
	ASSERT(lock_held_by_current_thread(lock));

	sema_init(&waiter.semaphore, 0);

	list_insert_ordered(&cond->waiters, &waiter.elem, &sem_priority_less, NULL);
	lock_release(lock);
	sema_down(&waiter.semaphore);
	lock_acquire(lock);
}

๊ธฐ์กด ์ฝ”๋“œ์—์„œ๋Š” ๋Œ€๊ธฐ ์Šค๋ ˆ๋“œ๋“ค์ด ์ˆœ์„œ๋Œ€๋กœ waiters ๋ฆฌ์ŠคํŠธ์— ์ถ”๊ฐ€๋˜๊ณ  ๊นจ์–ด๋‚œ๋‹ค.
์ˆ˜์ •ํ•œ ์ฝ”๋“œ์—์„œ๋Š” ๋Œ€๊ธฐ ์Šค๋ ˆ๋“œ๋“ค์ด ์šฐ์„ ์ˆœ์œ„ ์ˆœ์œผ๋กœ ์ •๋ ฌ๋œ ์œ„์น˜์— ์‚ฝ์ž…๋˜๊ณ  ๊นจ์–ด๋‚œ๋‹ค. ๋˜ํ•œ ๋Œ€๊ธฐ ์Šค๋ ˆ๋“œ์˜ ์šฐ์„ ์ˆœ์œ„๋ฅผ ์ €์žฅํ•˜์—ฌ ์ •๋ ฌ ๊ธฐ์ค€์œผ๋กœ ํ™œ์šฉ๋œ๋‹ค.


cond_signal()์„ ์ˆ˜์ •ํ•˜์ž.

์•„๋ž˜๋Š” cond_signal()์˜ ๊ธฐ๋ณธ์ฝ”๋“œ๋‹ค.

//threads/synch.c

/* If any threads are waiting on COND (protected by LOCK), then
   this function signals one of them to wake up from its wait.
   LOCK must be held before calling this function.

   An interrupt handler cannot acquire a lock, so it does not
   make sense to try to signal a condition variable within an
   interrupt handler. */
void
cond_signal (struct condition *cond, struct lock *lock UNUSED) {
	ASSERT (cond != NULL);
	ASSERT (lock != NULL);
	ASSERT (!intr_context ());
	ASSERT (lock_held_by_current_thread (lock));

	if (!list_empty (&cond->waiters))
		sema_up (&list_entry (list_pop_front (&cond->waiters),
					struct semaphore_elem, elem)->semaphore);
}

cond_signal ํ•จ์ˆ˜๋Š” ์กฐ๊ฑด ๋ณ€์ˆ˜ cond์™€ ๋ฝ lock์„ ์ธ์ž๋กœ ๋ฐ›์•„์™€์„œ ์‚ฌ์šฉํ•˜๊ณ , ๋Œ€๊ธฐ ์ค‘์ธ ์Šค๋ ˆ๋“œ ์ค‘ ํ•˜๋‚˜๋ฅผ ๊นจ์šด๋‹ค. ์ด๋ฅผ condition variable์˜waiters list๋ฅผ์šฐ์„ ์ˆœ์œ„๋กœ ์žฌ์ •๋ ฌ ํ•˜๋„๋ก ์ˆ˜์ •ํ•˜์ž.

์šฐ๋ฆฌํŒ€ ์ˆ˜์ • ์ฝ”๋“œ ๐Ÿค“

//threads/synch.c

void cond_signal(struct condition *cond, struct lock *lock UNUSED)
{
    ASSERT(cond != NULL);
    ASSERT(lock != NULL);
    ASSERT(!intr_context());
    ASSERT(lock_held_by_current_thread(lock));

    if (!list_empty(&cond->waiters))
    {

        list_sort(&cond->waiters, sem_priority_less, NULL);
        sema_up(&list_entry(list_pop_front(&cond->waiters),
                            struct semaphore_elem, elem)
                     ->semaphore);
    }
}

sema_up()์„ ํ•˜๊ธฐ ์ „ list_sort ํ•จ์ˆ˜๋ฅผ ์‚ฌ์šฉํ•˜์—ฌ waiters ๋ฆฌ์ŠคํŠธ๋ฅผ sem_priority_less ๋น„๊ต ํ•จ์ˆ˜๋ฅผ ๊ธฐ์ค€์œผ๋กœ ์ •๋ ฌํ•˜๋„๋ก ํ•˜์ž. sem_priority_less()๋Š” ์•„์ง ๊ตฌํ˜„์„ ์•ˆํ•ด์คฌ์ง€๋งŒ ์ด์ „์— priority_less()ํ•จ์ˆ˜์™€ ๊ตฌ์กฐ๊ฐ€ ๋น„์Šทํ–ˆ๋‹ค.


sema_cmp_priority()ํ•จ์ˆ˜๋ฅผ ๊ตฌํ˜„ํ•ด๋ณด์ž.

//include/threads/synch.h
bool sem_priority_less(const struct list_elem *a, const struct list_elem *b, void *aux);


//threads/synch.c

bool sem_priority_less(const struct list_elem *a, const struct list_elem *b, void *aux){
	struct semaphore_elem *sa = list_entry(a, struct semaphore_elem, elem);
	struct semaphore_elem *sb = list_entry(b, struct semaphore_elem, elem);

	struct thread *thread_a = list_entry(list_begin(&sa->semaphore.waiters), struct thread, elem);
	struct thread *thread_b = list_entry(list_begin(&sb->semaphore.waiters), struct thread, elem);

	return thread_a->priority > thread_b->priority;
}

sem_priority_less() ์ธ์ž๋กœ ๋“ค์–ด์˜ค๋Š” ๋Š” ๋‘ ๊ฐœ์˜ semaphore_elem ๊ตฌ์กฐ์ฒด๋ฅผ list_entry()ํ•จ์ˆ˜๋ฅผ ํƒ€๊ณ  ์˜ฌ๋ผ๊ฐ€ thread ๊ตฌ์กฐ์ฒด ์•ˆ์— ์žˆ๋Š” priority๊ฐ’์œผ๋กœ ๋น„๊ตํ•˜์—ฌ ์šฐ์„ ์ˆœ์œ„ ์ˆœ์„œ๋ฅผ ๊ฒฐ์ •ํ•˜๋Š” ๋น„๊ต ํ•จ์ˆ˜๋‹ค.
์ด๋Ÿฌํ•œ ๋ฐฉ์‹์œผ๋กœ sem_priority_less ํ•จ์ˆ˜๋Š” waiters ๋ฆฌ์ŠคํŠธ์—์„œ semaphore_elem์„ ์šฐ์„ ์ˆœ์œ„์— ๋”ฐ๋ผ ์ •๋ ฌํ•˜๋Š” ๋ฐ ์‚ฌ์šฉ๋œ๋‹ค.


๊ธธ๊ณ ๋„ ๊ธด synch ๋‚ด์šฉ์ •๋ฆฌ๊ฐ€ ๋๋‚ฌ๋‹ค. ์—ฌ๊ธฐ๊นŒ์ง€ ์ •์ƒ์ ์œผ๋กœ ๊ตฌํ˜„์ด ๋˜์—ˆ๋‹ค๋ฉด ๋‹ค์Œ๊ณผ ๊ฐ™์€ 14๊ฐœ์˜ fail์„ ๋ณผ ์ˆ˜ ์žˆ๋‹ค. ๐Ÿ˜ฎโ€๐Ÿ’จ

profile
^^*

0๊ฐœ์˜ ๋Œ“๊ธ€