16 min read

OSTEP 28 Locks

Table of Contents

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

1. ๋ฝ: ๊ธฐ๋ณธ ๊ฐœ๋…

balance = balance + 1;

๋‹ค์Œ๊ณผ ๊ฐ™์€ ์ž„๊ณ„ ์˜์—ญ์ด ์žˆ๋‹ค๊ณ  ํ•˜์ž.

๋ฝ์œผ๋กœ ์ž„๊ณ„ ์˜์—ญ์„ ๋‹ค์Œ๊ณผ ๊ฐ™์ด ๊ฐ์ŒŒ๋‹ค.

lock_t mutex; // ์ „์—ญ ๋ณ€์ˆ˜๋กœ ์„ ์–ธ๋œ ๋ฝ
...
lock(&mutex);
balance = balance + 1;
unlock(&mutex);

๋ฝ์€ ํ•˜๋‚˜์˜ ๋ณ€์ˆ˜์ด๋ฏ€๋กœ, ๋ฝ์„ ์‚ฌ์šฉํ•˜๊ธฐ ์œ„ํ•ด ๋จผ์ € ์„ ์–ธํ•ด์•ผ ํ•œ๋‹ค. ์ด ๋ฝ ๋ณ€์ˆ˜๋Š” ์‚ฌ์šฉ ๊ฐ€๋Šฅ ์ƒํƒœ, ์ฆ‰ ์–ด๋А ์“ฐ๋ ˆ๋“œ๋„ ๋ฝ์„ ๊ฐ€์ง€๊ณ  ์žˆ์ง€ ์•Š๊ฑฐ๋‚˜, ์‚ฌ์šฉ ์ค‘, ์ฆ‰ ์ž„๊ณ„ ์˜์—ญ์—์„œ ์ •ํ™•ํžˆ ํ•˜๋‚˜์˜ ์“ฐ๋ ˆ๋“œ๊ฐ€ ๋ฝ์„ ํš๋“ํ•œ ์ƒํƒœ์ด๋‹ค.

lock()๊ณผ unlock()์˜ ์˜๋ฏธ๋Š” ๊ฐ„๋‹จํ•˜๋‹ค. lock()์„ ํ˜ธ์ถœํ•˜์—ฌ ๋ฝ ํš๋“์„ ์‹œ๋„ํ•œ๋‹ค. ๋งŒ์•ฝ ์–ด๋–ค ์“ฐ๋ ˆ๋“œ๋„ ๋ฝ์„ ๊ฐ€์ง€๊ณ  ์žˆ์ง€ ์•Š๋‹ค๋ฉด ๊ทธ ์“ฐ๋ ˆ๋“œ๋Š” ๋ฝ์„ ํš๋“ํ•˜์—ฌ ์ž„๊ณ„ ์˜์—ญ์œผ๋กœ ์ง„์ž…ํ•œ๋‹ค. ์ด๋ ‡๊ฒŒ ์ง„์ž…ํ•œ ์“ฐ๋ ˆ๋“œ๋ฅผ ๋ฝ ์†Œ์œ ์ž (owner) ๋ผ๊ณ  ๋ถ€๋ฅธ๋‹ค. ๋งŒ์•ฝ ๋‹ค๋ฅธ ์“ฐ๋ ˆ๋“œ๊ฐ€ lock()์„ ํ˜ธ์ถœํ•œ๋‹ค๋ฉด, ์‚ฌ์šฉ ์ค‘์ธ ๋™์•ˆ์—๋Š” lock() ํ•จ์ˆ˜๊ฐ€ ๋ฆฌํ„ดํ•˜์ง€ ์•Š๋Š”๋‹ค.

๋ฝ ์†Œ์œ ์ž๊ฐ€ unlock()์„ ํ˜ธ์ถœํ•œ๋‹ค๋ฉด ๋ฝ์€ ์ด์ œ ๋‹ค์‹œ ์‚ฌ์šฉ ๊ฐ€๋Šฅํ•œ ์ƒํƒœ๊ฐ€ ๋œ๋‹ค. ์–ด๋–ค ์“ฐ๋ ˆ๋“œ๋„ ์ด ๋ฝ์„ ๋Œ€๊ธฐํ•˜๊ณ  ์žˆ์ง€ ์•Š๋‹ค๋ฉด (์–ด๋–ค ์“ฐ๋ ˆ๋“œ๋„ lock()์„ ํ˜ธ์ถœํ•˜์—ฌ ๋ฉˆ์ถฐ ์žˆ๋˜ ์ƒํƒœ๊ฐ€ ์•„๋‹ˆ๋ผ๋ฉด) ๋ฝ์˜ ์ƒํƒœ๋Š” ์‚ฌ์šฉ ๊ฐ€๋Šฅ์œผ๋กœ ์œ ์ง€๋œ๋‹ค.

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

2. Pthread ๋ฝ

์“ฐ๋ ˆ๋“œ ๊ฐ„ ์ƒํ˜ธ ๋ฐฐ์ œ (mutual exclusion) ๊ธฐ๋Šฅ์„ ์ œ๊ณตํ•˜๊ธฐ ๋•Œ๋ฌธ์— POSIX ๋ผ์ด๋ธŒ๋Ÿฌ๋ฆฌ๋Š” ๋ฝ์„ mutex ๋ผ๊ณ  ๋ถ€๋ฅธ๋‹ค. ์ƒํ˜ธ ๋ฐฐ์ œ๋Š” ํ•œ ์“ฐ๋ ˆ๋“œ๊ฐ€ ์ž„๊ณ„ ์˜์—ญ ๋‚ด์— ์žˆ๋‹ค๋ฉด, ์ด ์“ฐ๋ ˆ๋“œ์˜ ๋™์ž‘์ด ๋๋‚  ๋•Œ๊นŒ์ง€ ๋‹ค๋ฅธ ์“ฐ๋ ˆ๋“œ๊ฐ€ ์ž„๊ณ„ ์˜์—ญ์— ๋“ค์–ด์˜ฌ ์ˆ˜ ์—†๋„๋ก ์ œํ•œํ•œ๋‹ค๊ณ  ํ•ด์„œ ๋ถ™์—ฌ์ง„ ์ด๋ฆ„์ด๋‹ค.

๋ž˜ํผ๋ฅผ ์‚ฌ์šฉํ•˜์—ฌ ๋ฝ๊ณผ ์–ธ๋ฝ์‹œ์— ์—๋Ÿฌ๋ฅผ ํ™•์ธํ•˜๋„๋ก ํ•จ

pthread_mutex_t lock = PTHREAD_MUTEX_INITIALIZER;

Pthread_mutex_lock(&lock); // pthread_mutex_lock()์„ ์œ„ํ•œ ๋ž˜ํผ.
balance = balance + 1;
Pthread_mutex_unlock(&lock);

POSIX ๋ฐฉ์‹์€ ๋ณ€์ˆ˜๋ช…์„ ์ง€์ •ํ•˜์—ฌ ๋ฝ๊ณผ ์–ธ๋ฝ ํ•จ์ˆ˜์— ์ „๋‹ฌํ•œ๋‹ค. ๋‹ค๋ฅธ ๋ณ€์ˆ˜๋ฅผ ๋ณดํ˜ธํ•˜๊ธฐ ์œ„ํ•ด ๋‹ค๋ฅธ ๋ฝ์„ ์‚ฌ์šฉํ• ์ˆ˜๋„ ์žˆ๊ธฐ ๋•Œ๋ฌธ์ด๋‹ค. ์ด๋ฅผ ํ†ตํ•ด ์—ฌ๋Ÿฌ๊ฐ€์ง€ ๋ฐฉ์‹์œผ๋กœ ๋ฝ์„ ๊ตฌํ˜„ํ•  ์ˆ˜ ์žˆ๋‹ค.

์„ธ๋ฐ€ํ•œ ๋ฝ๊ณผ ๊ฑฐ์นœ ๋ฝ ์ „๋žต

๊ฑฐ์นœ ๋ฝ (Coarse-Grained Locking)

  • ํ•˜๋‚˜์˜ ๋ฝ์ด ํฐ ์ž„๊ณ„ ์˜์—ญ์„ ์ œ์–ดํ•จ.
  • ์‰ฝ๊ฒŒ ๊ตฌํ˜„ํ•  ์ˆ˜ ์žˆ์ง€๋งŒ, ๋ณ‘๋ ฌ์„ฑ์ด ์ œํ•œ๋จ.

์„ธ๋ฐ€ํ•œ ๋ฝ (Fine-Grained Locking)

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

3. ๋ฝ ๊ตฌํ˜„

์ด๋ฒˆ ์žฅ์—์„œ ์–ด๋–ป๊ฒŒ ๋ฝ์„ ๋งŒ๋“ค์–ด์•ผ ํ•˜๋Š”์ง€, ์–ด๋–ค ์ข…๋ฅ˜์˜ ํ•˜๋“œ์›จ์–ด ์ง€์›์ด ํ•„์š”ํ•œ์ง€, ์šด์˜์ฒด์ œ๋Š” ๋ฌด์—‡์„ ์ง€์›ํ•ด์•ผ ํ•˜๋Š”์ง€์— ๋Œ€ํ•ด ๋‹ค๋ฃฐ ๊ฒƒ์ด๋‹ค.

ํšจ์œจ์ ์ธ ๋ฝ์€ ์–ด๋–ป๊ฒŒ ๋งŒ๋“ค์–ด์•ผ ํ•˜๋Š”๊ฐ€? ํšจ์œจ์ ์ธ ๋ฝ์€ ๋‚ฎ์€ ๋น„์šฉ์œผ๋กœ ์ƒํ˜ธ ๋ฐฐ์ œ ๊ธฐ๋ฒ•์„ ์ œ๊ณตํ•˜๊ณ  ๋‹ค์Œ์— ๋‹ค๋ฃฐ ๋ช‡ ๊ฐ€์ง€ ์†์„ฑ๋“ค์„ ์ถ”๊ฐ€๋กœ ๊ฐ€์ ธ์•ผ ํ•œ๋‹ค. ์–ด๋–ค ํ•˜๋“œ์›จ์–ด ์ง€์›์ด ํ•„์š”ํ•œ๊ฐ€? ์–ด๋–ค ์šด์˜์ฒด์ œ ์ง€์›์ด ํ•„์š”ํ•œ๊ฐ€?

4. ๋ฝ์˜ ํ‰๊ฐ€

์ƒํ˜ธ ๋ฐฐ์ œ (mutual exclusion)

  • ๊ฐ€์žฅ ๊ธฐ๋ณธ ์—ญํ• .
  • ์ž„๊ณ„ ์˜์—ญ ๋‚ด๋กœ ๋‹ค์ˆ˜์˜ ์“ฐ๋ ˆ๋“œ๊ฐ€ ์ง„์ž…ํ•˜๋Š” ๊ฒƒ์„ ๋ง‰์„ ์ˆ˜ ์žˆ๋Š”์ง€ ๊ฒ€์‚ฌํ•ด์•ผ ํ•จ.

๊ณต์ •์„ฑ (fairness)

  • ์—ฌ๋Ÿฌ ์“ฐ๋ ˆ๋“œ๋“ค์ด ๋ฝ์„ ๋ฒˆ๊ฐˆ์•„๊ฐ€๋ฉด์„œ ํš๋“ํ•  ์ˆ˜ ์žˆ์–ด์•ผ ํ•จ.
  • ๋ฝ์„ ์ „ํ˜€ ์–ป์ง€ ๋ชปํ•ด ๊ตถ์ฃผ๋ฆฌ๋Š” ๊ฒฝ์šฐ๊ฐ€ ๋ฐœ์ƒํ•˜๋ฉด ์•ˆ ๋จ.

์„ฑ๋Šฅ (performance)

  • ๋ฝ ์‚ฌ์šฉ์— ๋Œ€ํ•œ ์‹œ๊ฐ„์  ์˜ค๋ฒ„ํ—ค๋“œ๋ฅผ ํ‰๊ฐ€ํ•ด์•ผ ํ•œ๋‹ค.
  • ํ•˜๋‚˜์˜ ์“ฐ๋ ˆ๋“œ๊ฐ€ ์‹คํ–‰ ์ค‘์— ๋ฝ์„ ํš๋“ํ•˜๊ณ  ํ•ด์ œํ•˜๋Š” ๊ณผ์ •์—์„œ ๋ฐœ์ƒํ•˜๋Š” ๋ถ€ํ•˜๊ฐ€ ์–ผ๋งˆ๋‚˜ ๋˜๋Š”๊ฐ€?

5. ์ธํ„ฐ๋ŸฝํŠธ ์ œ์–ด

์ดˆ์ฐฝ๊ธฐ ๋‹จ์ผ ํ”„๋กœ์„ธ์„œ ์‹œ์Šคํ…œ์—์„œ๋Š” ์ƒํ˜ธ ๋ฐฐ์ œ ์ง€์›์„ ์œ„ํ•ด ์ž„๊ณ„ ์˜์—ญ ๋‚ด์—์„œ ์ธํ„ฐ๋ŸฝํŠธ๋ฅผ ๋น„ํ™œ์„ฑํ™” ํ•˜๋Š” ๋ฐฉ๋ฒ•์„ ์‚ฌ์šฉํ–ˆ๋‹ค.

void lock() {
	DisableInterrupts();
}
void unlock() {
	EnableInterrupts();
}

์ด ๋ฐฉ๋ฒ•์˜ ์žฅ์ ์€ ๋‹จ์ˆœํ•˜๋‹ค๋Š” ๊ฒƒ์ด๊ณ , ๋‹จ์ ์€ ๋งŽ๋‹ค.

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

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

6. Test-And-Set (Atomic Exchange)

๋ฉ€ํ‹ฐ ํ”„๋กœ์„ธ์„œ ์‹œ์Šคํ…œ์—์„œ๋Š” ์ธํ„ฐ๋ŸฝํŠธ๋ฅผ ์ค‘์ง€์‹œํ‚ค๋Š” ๊ฒƒ์ด ์˜๋ฏธ๊ฐ€ ์—†๊ธฐ ๋•Œ๋ฌธ์— ์‹œ์Šคํ…œ ์„ค๊ณ„์ž๋“ค์€ ๋ฝ ์ง€์›์„ ์œ„ํ•œ ํ•˜๋“œ์›จ์–ด๋ฅผ ์„ค๊ณ„ํ•˜๊ธฐ ์‹œ์ž‘ํ–ˆ๋‹ค. ์˜ค๋Š˜๋‚ ์—๋Š” ๋ชจ๋“  ์‹œ์Šคํ…œ์ด ์ด๋Ÿฌํ•œ ์ง€์› ๊ธฐ๋Šฅ์„ ๊ฐ€์ง€๊ณ  ์žˆ๋‹ค.

ํ•˜๋“œ์›จ์–ด ๊ธฐ๋ฒ• ์ค‘ ๊ฐ€์žฅ ๊ธฐ๋ณธ์€ Test-And-Set ๋ช…๋ น์–ด ๋˜๋Š” ์›์ž์  ๊ต์ฒด (atomic exchange) ๋ผ๊ณ  ๋ถˆ๋ฆฌ๋Š” ๊ธฐ๋ฒ•์ด๋‹ค. ์ด๋ฅผ ์ดํ•ดํ•˜๊ธฐ ์œ„ํ•ด ๊ฐ„๋‹จํ•œ ํ”Œ๋ž˜๊ทธ ๋ณ€์ˆ˜๋กœ ๋ฝ์„ ๊ตฌํ˜„ํ•ด๋ณด์ž.

typedef struct __lock_t { int flag; } lock_t;

void init(lock_t *mutex) {
	// 0: ๋ฝ ์‚ฌ์šฉ ๊ฐ€๋Šฅ
	// 1: ๋ฝ ์‚ฌ์šฉ ์ค‘
	mutexโˆ’>flag = 0;
}

void lock(lock_t *mutex) {
	while (mutexโˆ’>flag == 1) // flag ๋ณ€์ˆ˜๋ฅผ ๊ฒ€์‚ฌ (test) ํ•œ๋‹ค
	; // spinโˆ’wait (do nothing)
	mutexโˆ’>flag = 1; // ์ด์ œ ์„ค์ • (set) ํ•œ๋‹ค
}

void unlock(lock_t *mutex) {
	mutexโˆ’>flag = 0;
}

๊ฐ„๋‹จํ•œ ๋ณ€์ˆ˜๋ฅผ ์‚ฌ์šฉํ•ด ์“ฐ๋ ˆ๋“œ๊ฐ€ ๋ฝ์„ ํš๋“ํ–ˆ๋Š”์ง€ ๋‚˜ํƒ€๋‚ธ๋‹ค. ์ž„๊ณ„ ์˜์—ญ์— ์ง„์ž…ํ•˜๋Š” ์ฒซ ์“ฐ๋ ˆ๋“œ๊ฐ€ lock()์„ ํ˜ธ์ถœํ•˜์—ฌ ํ”Œ๋ž˜๊ทธ๊ฐ€ 1์ธ์ง€ ๊ฒ€์‚ฌ(test) ํ•˜๊ณ  ํ”Œ๋ž˜๊ทธ์˜ ๊ฐ’์„ 1๋กœ ์„ค์ •(set) ํ•˜์—ฌ ์ด ์“ฐ๋ ˆ๋“œ๊ฐ€ ๋ฝ์„ ๋ณด์œ (hold) ํ•˜๊ณ  ์žˆ๋‹ค๊ณ  ํ‘œ์‹œํ•œ๋‹ค. ์ž„๊ณ„ ์˜์—ญ์—์„œ ๋‚˜์˜ค๋ฉด ์“ฐ๋ ˆ๋“œ๊ฐ€ unlock()์„ ํ˜ธ์ถœํ•˜์—ฌ ํ”Œ๋ž˜๊ทธ ๊ฐ’์„ ์ดˆ๊ธฐํ™”ํ•˜๊ณ , ๋ฝ์„ ๋” ์ด์ƒ ๋ณด์œ ํ•˜๊ณ  ์žˆ์ง€ ์•Š๋‹ค๊ณ  ํ‘œ์‹œํ•œ๋‹ค.

๋งŒ์•ฝ ์ฒซ ๋ฒˆ์งธ ์“ฐ๋ ˆ๋“œ๊ฐ€ ์ž„๊ณ„ ์˜์—ญ ๋‚ด์— ์žˆ์„ ๋•Œ ๋‹ค๋ฅธ ์“ฐ๋ ˆ๋“œ๊ฐ€ lock()์„ ํ˜ธ์ถœํ•˜๋ฉด ๊ทธ ์“ฐ๋ ˆ๋“œ๋Š” while๋ฌธ์œผ๋กœ spin-wait์„ ํ•˜๋ฉฐ ์ฒ˜์Œ ์“ฐ๋ ˆ๋“œ๊ฐ€ unlock()์„ ํ˜ธ์ถœํ•˜์—ฌ ํ”Œ๋ž˜๊ทธ๋ฅผ ์ดˆ๊ธฐํ™”ํ•˜๊ธฐ๋ฅผ ๊ธฐ๋‹ค๋ฆฐ๋‹ค. ์ฒ˜์Œ ์“ฐ๋ ˆ๋“œ๊ฐ€ ํ”Œ๋ž˜๊ทธ๋ฅผ ์ดˆ๊ธฐํ™”ํ•˜๋ฉด ๋Œ€๊ธฐํ•˜๋˜ ์“ฐ๋ ˆ๋“œ๋Š” while ๋ฌธ์—์„œ ๋น ์ ธ๋‚˜์™€ ํ”Œ๋ž˜๊ทธ๋ฅผ 1๋กœ ์„ค์ •ํ•˜๊ณ  ์ž„๊ณ„ ์˜์—ญ ๋‚ด๋กœ ์ง„์ž…ํ•œ๋‹ค.

์ด ์ฝ”๋“œ์—๋Š” ๋‘ ๊ฐ€์ง€ ๋ฌธ์ œ๊ฐ€ ์žˆ๋‹ค.

์ •ํ™•์„ฑ

OSTEP 28 Locks-1694380377043.jpeg

์‹œ์ž‘ํ•  ๋•Œ flag = 0์ด๋ผ ํ•˜์ž. ์“ฐ๋ ˆ๋“œ 1์ด flag = 1์„ ์‹คํ–‰ํ•˜๊ธฐ ์ง์ „์— ์ธํ„ฐ๋ŸฝํŠธ๊ฐ€ ์ผ์–ด๋‚œ๋‹ค๋ฉด? ๋‘ ์“ฐ๋ ˆ๋“œ ๋ชจ๋‘ ํ”Œ๋ž˜๊ทธ๋ฅผ 1๋กœ ์„ค์ •ํ•˜๋„๋ก ํ•˜๋Š” ์ธํ„ฐ๋ŸฝํŠธ ํƒ€์ด๋ฐ์ด ์กด์žฌํ•œ๋‹ค. ๋‘ ์“ฐ๋ ˆ๋“œ ๋ชจ๋‘ ์ž„๊ณ„ ์˜์—ญ์— ์ง„์ž…ํ•˜๊ฒŒ ๋œ๋‹ค. ์ž˜๋ชป ๋งŒ๋“ค์—ˆ๋‹ค.

์„ฑ๋Šฅ

spin wait์„ ํ†ตํ•ด ํ”Œ๋ž˜๊ทธ์˜ ๊ฐ’์„ ๋ฌดํ•œํžˆ ๊ฒ€์‚ฌํ•˜๋Š”๋ฐ, ์ด๋Š” ์„ฑ๋Šฅ์ƒ ์ข‹์ง€ ๋ชปํ•˜๋‹ค. ํŠนํžˆ ๋‹จ์ผ ํ”„๋กœ์„ธ์„œ์—์„œ. ๋ฝ์„ ์†Œ์œ ํ•œ ์“ฐ๋ ˆ๋“œ์กฐ์ฐจ ์‹คํ–‰ํ•˜๊ธฐ ํž˜๋“ค๋„๋ก ํ•œ๋‹ค.

7. ์ง„์งœ ๋Œ์•„๊ฐ€๋Š” ์Šคํ•€ ๋ฝ์˜ ๊ตฌํ˜„

์•ž์„œ ๋‹ค๋ฃฌ ์˜ˆ์ œ๋Š” ํ•˜๋“œ์›จ์–ด ์ง€์› ์—†์ด๋Š” ๋™์ž‘์ด ๋ถˆ๊ฐ€๋Šฅํ–ˆ๋‹ค. ๋‹คํ–‰ํžˆ๋„ ์–ด๋–ค ์‹œ์Šคํ…œ์€ ์ด ๊ฐœ๋…์— ๊ทผ๊ฐ„ํ•œ ๋ฝ ๊ตฌํ˜„์„ ์œ„ํ•œ ์–ด์…ˆ๋ธ”๋ฆฌ ๋ช…๋ น์–ด๋ฅผ ์ œ๊ณตํ•œ๋‹ค. SPARC์—์„œ๋Š” ldstub, x86์—์„œ๋Š” ์›์ž์  ๊ต์ฒด ๋ช…๋ น์–ด์ธ xchg์ด๋‹ค. ๊ธฐ๋ณธ์ ์œผ๋กœ ๋™์ผํ•œ ์ผ์„ ์ˆ˜ํ–‰ํ•œ๋‹ค. ์ผ๋ฐ˜์ ์œผ๋กœ Test-And-Set ์ด๋ผ๊ณ  ๋ถˆ๋ฆฐ๋‹ค. TestAndSet ๋™์ž‘์„ ์ •์˜ํ•ด๋ณด์ž.

int TestAndSet(int *old_ptr, int new) {
	int old = *old_ptr; // old_ptr์˜ ์ด์ „ ๊ฐ’์„ ๊ฐ€์ ธ์˜ด
	*old_ptr = new; // old_ptr ์— new ๊ฐ’์„ ์ €์žฅํ•จ
	return old; // old์˜ ๊ฐ’์„ ๋ฐ˜ํ™˜ํ•จ
}

TestAndSet ๋ช…๋ น์–ด๊ฐ€ ํ•˜๋Š” ๋™์ž‘์€ ๋‹ค์Œ๊ณผ ๊ฐ™๋‹ค. ptr์ด ๊ฐ€๋ฆฌํ‚ค๊ณ  ์žˆ๋˜ ์˜ˆ์ „์˜ ๊ฐ’์„ ๋ฐ˜ํ™˜ํ•˜๊ณ , ๋™์‹œ์— new ๊ฐ’์„ ptr์— ์ €์žฅํ•œ๋‹ค. ์—ฌ๊ธฐ์„œ์˜ ํ•ต์‹ฌ์€ ์ด ๋™์ž‘๋“ค์ด ์›์ž์ ์œผ๋กœ ์ˆ˜ํ–‰๋œ๋‹ค๋Š” ๊ฒƒ์ด๋‹ค. ์ด์ „ ๊ฐ’์„ ๊ฒ€์‚ฌ (test -> ๋ฐ˜ํ™˜๋˜๋Š” ๊ฐ’) ํ•˜๋Š” ๋™์‹œ์— ๋ฉ”๋ชจ๋ฆฌ์— ์ƒˆ๋กœ์šด ๊ฐ’์„ ์„ค์ • (set) ํ•œ๋‹ค.

์ด ๋ช…๋ น์–ด๋งŒ์œผ๋กœ ๊ฐ„๋‹จํ•œ spin lock์„ ๋งŒ๋“ค ์ˆ˜ ์žˆ๋‹ค.

typedef struct __lock_t {
	int flag;
} lock_t;

void init(lock_t *lock) {
	// 0์€ ๋ฝ์ด ํš๋“ ๊ฐ€๋Šฅํ•œ ์ƒํƒœ
	// 1์€ ๋ฝ์„ ํš๋“ํ–ˆ์Œ
	lockโˆ’>flag = 0;
}

void lock(lock_t *lock) {
	while (TestAndSet(&lockโˆ’>flag, 1) == 1)
	; // spin
}

void unlock(lock_t *lock) {
	lockโˆ’>flag = 0;
}

์ž‘๋™ ์›๋ฆฌ๋ฅผ ํŒŒ์•…ํ•ด๋ณด๋„๋ก ํ•˜์ž.

์ฒ˜์Œ ์“ฐ๋ ˆ๋“œ๊ฐ€ lock()์„ ํ˜ธ์ถœํ•˜๊ณ , ๋‹ค๋ฅธ ์–ด๋–ค ์“ฐ๋ ˆ๋“œ๋„ ํ˜„์žฌ ๋ฝ์„ ๋ณด์œ ํ•˜๊ณ  ์žˆ์ง€ ์•Š๋‹ค๊ณ  ํ•˜์ž. ๊ทธ๋Ÿผ ํ˜„์žฌ flag์˜ ๊ฐ’์€ 0์ด๋‹ค. TestAndSet(flag, 1)์„ ํ˜ธ์ถœํ•˜๋ฉด ๋ฐ˜ํ™˜ ๊ฐ’์€ 0 ์ด๋ผ while๋ฌธ์„ ํƒˆ์ถœํ•  ์ˆ˜ ์žˆ๋‹ค. ๊ทธ๋ฆฌ๊ณ  flag๋Š” 1์ด ๋œ๋‹ค. ์ดํ›„ ์ด ์“ฐ๋ ˆ๋“œ๊ฐ€ ๋™์ž‘์„ ๋๋งˆ์น˜๋ฉด unlock()์„ ํ˜ธ์ถœํ•˜์—ฌ flag ๊ฐ’์„ ๋‹ค์‹œ 0์œผ๋กœ ๋ณ€๊ฒฝํ•œ๋‹ค.

์ฒ˜์Œ ์“ฐ๋ ˆ๋“œ๊ฐ€ ๋ฝ์„ ํš๋“ํ•˜์—ฌ flag๊ฐ€ 1์ธ ์ƒํƒœ์—์„œ, ๋‘ ๋ฒˆ์งธ ์“ฐ๋ ˆ๋“œ๊ฐ€ lock()์„ ํ˜ธ์ถœํ•œ๋‹ค๊ณ  ํ•ด๋ณด์ž. TestAndSet(flag, 1)์„ ํ˜ธ์ถœํ•˜๋ฉด ๋ฐ˜ํ™˜ ๊ฐ’์ด 1 ์ด๋ผ while๋ฌธ์„ ํƒˆ์ถœํ•  ์ˆ˜ ์—†๋‹ค. ๋ฝ์„ ๋ณด์œ ํ•˜๊ณ  ์žˆ๋Š” ์“ฐ๋ ˆ๋“œ๊ฐ€ ์กด์žฌํ•˜๋Š” ํ•œ TestAndSet(flag, 1)์€ ๊ณ„์† 1์„ ๋ฐ˜ํ™˜ํ•œ๋‹ค.

๋ฝ์„ ๋ณด์œ ํ•˜๊ณ  ์žˆ๋Š” ์ฒ˜์Œ ์“ฐ๋ ˆ๋“œ๊ฐ€ flag ๊ฐ’์„ 0์œผ๋กœ ๋ณ€๊ฒฝํ•˜๋ฉด, ๋‘ ๋ฒˆ์งธ ์“ฐ๋ ˆ๋“œ๊ฐ€ TestAndSet(flag, 1)์„ ํ˜ธ์ถœํ–ˆ์„ ๋•Œ ๋ฐ˜ํ™˜ ๊ฐ’์ด 0์ด ๋˜์–ด while๋ฌธ์„ ํƒˆ์ถœํ•  ์ˆ˜ ์žˆ๊ฒŒ ๋œ๋‹ค.

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

8. ์Šคํ•€ ๋ฝ ํ‰๊ฐ€

๋ฝ์—์„œ ๊ฐ€์žฅ ์ค‘์š”ํ•œ ์ธก๋ฉด์€ ์ƒํ˜ธ ๋ฐฐ์ œ์˜ ์ •ํ™•์„ฑ ์ด๋‹ค. ์ƒํ˜ธ ๋ฐฐ์ œ๊ฐ€ ๊ฐ€๋Šฅํ•˜๋‹ค๋ฉด ์Šคํ•€ ๋ฝ์€ ์ž„์˜์˜ ์‹œ๊ฐ„์— ๋‹จ ํ•˜๋‚˜์˜ ์“ฐ๋ ˆ๋“œ๋งŒ์ด ์ž„๊ณ„ ์˜์—ญ์— ์ง„์ž…ํ•  ์ˆ˜ ์žˆ๋„๋ก ํ•œ๋‹ค.

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

๋งˆ์ง€๋ง‰ ํ•ญ๋ชฉ์€ ์„ฑ๋Šฅ์ด๋‹ค. ์Šคํ•€ ๋ฝ์„ ์‚ฌ์šฉํ•  ๋•Œ ์–ผ๋งˆ๋‚˜ ๋น„์šฉ์„ ์ง€๋ถˆํ•ด์•ผ ํ• ๊นŒ? ๋‹จ์ผ CPU์˜ ๊ฒฝ์šฐ ์Šคํ•€ ๋ฝ์ด ๊ฐ–๋Š” ์„ฑ๋Šฅ ์˜ค๋ฒ„ํ—ค๋“œ๋Š” ์ƒ๋‹นํžˆ ํด ์ˆ˜ ์žˆ๋‹ค. NN๊ฐœ ์ค‘ Nโˆ’1N-1๊ฐœ์˜ ๋‹ค๋ฅธ ์“ฐ๋ ˆ๋“œ๊ฐ€ ๋ฝ์„ ํš๋“ํ•˜๋ ค๊ณ  ํ•  ๋•Œ, ์Šค์ผ€์ค„๋Ÿฌ๊ฐ€ ์ด๋“ค์„ ํ•œ ๋ฒˆ์”ฉ ๊นจ์šธ ์ˆ˜๋„ ์žˆ๋‹ค. CPU๊ฐ€ ์—ฌ๋Ÿฌ ๊ฐœ์ธ ๊ฒฝ์šฐ (์“ฐ๋ ˆ๋“œ์˜ ๊ฐœ์ˆ˜์™€ CPU์˜ ๊ฐœ์ˆ˜๊ฐ€ ๋น„์Šทํ•˜๋‹ค๋ฉด) ์Šคํ•€ ๋ฝ์€ ๊ฝค ํ•ฉ๋ฆฌ์ ์œผ๋กœ ๋™์ž‘ํ•œ๋‹ค. CPU 1์—์„œ ์‹คํ–‰์ค‘์ธ A๊ฐ€ ๋ฝ์„ ํš๋“ํ•œ ํ›„ B๊ฐ€ ๋ฝ์„ ํš๋“ํ•˜๋ ค๊ณ  ํ•œ๋‹ค๋ฉด CPU 2์—์„œ ๊ธฐ๋‹ค๋ฆฌ๊ธฐ ๋•Œ๋ฌธ์— ๊ธˆ๋ฐฉ ๋ฝ์„ ํš๋“ํ•  ์ˆ˜ ์žˆ์„ ๊ฒƒ์ด๋‹ค.

9. Compare-And-Swap

๋˜ ๋‹ค๋ฅธ ํ•˜๋“œ์›จ์–ด ๊ธฐ๋ฒ•์€ SPARC์˜ Compare-And-Swap, x86์˜ Compare-And-Exchange๊ฐ€ ์žˆ๋‹ค.

int CompareAndSwap(int *ptr, int expected, int new) {
	int actual = *ptr;
	if (actual == expected)
		*ptr = new;
	return actual;
}

Compare-And-Swap ๊ธฐ๋ฒ•์˜ ๊ธฐ๋ณธ ๊ฐœ๋…์€ ptr์ด ๊ฐ€๋ฆฌํ‚ค๊ณ  ์žˆ๋Š” ์ฃผ์†Œ์˜ ๊ฐ’์ด expected ๋ณ€์ˆ˜์™€ ์ผ์น˜ํ•˜๋Š”์ง€ ๊ฒ€์‚ฌํ•˜๋Š” ๊ฒƒ์ด๋‹ค. ๋งŒ์•ฝ ์ผ์น˜ํ•œ๋‹ค๋ฉด ptr์ด ๊ฐ€๋ฆฌํ‚ค๋Š” ์ฃผ์†Œ์˜ ๊ฐ’์„ ์ƒˆ๋กœ์šด ๊ฐ’์œผ๋กœ ๋ณ€๊ฒฝํ•œ๋‹ค. ๋ถˆ์ผ์น˜ํ•œ๋‹ค๋ฉด ๋ณ€๊ฒฝํ•˜์ง€ ์•Š๋Š”๋‹ค. ์›๋ž˜์˜ ๋ฉ”๋ชจ๋ฆฌ ๊ฐ’์„ ๋ฐ˜ํ™˜ํ•˜์—ฌ CompareAndSwap์„ ํ˜ธ์ถœํ•œ ์ฝ”๋“œ๊ฐ€ ๋ฝ ํš๋“์˜ ์„ฑ๊ณต ์—ฌ๋ถ€๋ฅผ ์•Œ ์ˆ˜ ์žˆ๋„๋ก ํ•œ๋‹ค.

์•ž์„œ ์ž‘์„ฑํ•œ Test-And-Set ๋ฐฉ๋ฒ•์„ ์‚ฌ์šฉํ–ˆ์„ ๋•Œ์™€ ๊ฐ™์€ ๋ฐฉ๋ฒ•์œผ๋กœ ๋ฝ์„ ๋งŒ๋“ค ์ˆ˜ ์žˆ๋‹ค.

typedef struct __lock_t {
	int flag;
} lock_t;

void init(lock_t *lock) {
	// 0์€ ๋ฝ์ด ํš๋“ ๊ฐ€๋Šฅํ•œ ์ƒํƒœ
	// 1์€ ๋ฝ์„ ํš๋“ํ–ˆ์Œ
	lockโˆ’>flag = 0;
}

void lock(lock_t *lock) {
while (CompareAndSwap(&lockโˆ’>flag, 0, 1) == 1)
	; // spin
}

void unlock(lock_t *lock) {
	lockโˆ’>flag = 0;
}

๋งจ ์ฒ˜์Œ ๋ฝ์„ ํš๋“ํ•˜๋Š” ์“ฐ๋ ˆ๋“œ๋Š”, 0์„ 1๋กœ ๋ฐ”๊พธ๋Š”๋ฐ ์„ฑ๊ณตํ•ด์„œ 0์„ ๋ฐ˜ํ™˜๋ฐ›๊ณ  (actual == 0) ๋ฃจํ”„๋ฅผ ํƒˆ์ถœํ•œ๋‹ค. ๊ทธ ์ดํ›„ ์ ‘๊ทผํ•˜๋Š” ์“ฐ๋ ˆ๋“œ๋Š” expected๋Š” 0, flag๋Š” 1์ด๋ผ 1์„ ๋ฐ˜ํ™˜๋ฐ›๊ณ  (actual == 1) ๋ฃจํ”„๋ฅผ ํƒˆ์ถœํ•  ์ˆ˜ ์—†๋‹ค.

CompareAndSwap ๋ช…๋ น์–ด๋Š” TestAndSet ๋ช…๋ น์–ด๋ณด๋‹ค ๋” ๊ฐ•๋ ฅํ•˜๋‹ค. ๋Œ€๊ธฐ์—†๋Š” ๋™๊ธฐํ™” (wait-free synchronization) ์„ ๋‹ค๋ฃฐ ๋•Œ ๊ฐ•๋ ฅํ•จ์„ ์•Œ๊ฒŒ ๋  ๊ฒƒ์ด๋‹ค.

10. Load-Linked ๊ทธ๋ฆฌ๊ณ  Store-Conditional

์–ด๋–ค ํ”Œ๋žซํผ์€ ์ž„๊ณ„ ์˜์—ญ ์ง„์ž… ์ œ์–ด ํ•จ์ˆ˜๋ฅผ ์ œ์ž‘ํ•˜๊ธฐ ์œ„ํ•œ ๋ช…๋ น์–ด ์Œ์„ ์ œ๊ณตํ•œ๋‹ค. MIPS ๊ตฌ์กฐ์—์„œ๋Š” load-linked์™€ store-conditional ๋ช…๋ น์–ด๋ฅผ ์•ž๋’ค๋กœ ์‚ฌ์šฉํ•˜์—ฌ ๋ฝ์ด๋‚˜ ๊ธฐํƒ€ ๋ณ‘ํ–‰ ์—ฐ์‚ฐ์„ ์œ„ํ•œ ์ž๋ฃŒ ๊ตฌ์กฐ๋ฅผ ๋งŒ๋“ค ์ˆ˜ ์žˆ๋‹ค.

int LoadLinked(int *ptr) {
	return *ptr;
}

int StoreConditional(int *ptr, int value) {
	if (no one has updated *ptr since the LoadLinked to this address) {
		*ptr = value;
		return 1; // ๊ฐฑ์‹  ์„ฑ๊ณต
	} else {
		return 0; // ๊ฐฑ์‹  ์‹คํŒจ
	}
}

LoadLinked๋Š” ์ผ๋ฐ˜ ๋กœ๋“œ ๋ช…๋ น์–ด์™€ ๊ฐ™์ด ๋ฉ”๋ชจ๋ฆฌ ๊ฐ’์„ ๋ ˆ์ง€์Šคํ„ฐ์— ์ €์žฅํ•œ๋‹ค. StoreConditional ๋ช…๋ น์–ด๋Š” ๋™์ผํ•œ ์ฃผ์†Œ์— ๋‹ค๋ฅธ store๊ฐ€ ์—†์—ˆ๋˜ ๊ฒฝ์šฐ์—๋งŒ ์ €์žฅ์„ ์„ฑ๊ณตํ•œ๋‹ค. ์„ฑ๊ณตํ•œ ๊ฒฝ์šฐ LoadLinked๊ฐ€ ํƒ‘์žฌํ–ˆ๋˜ ๊ฐ’์„ ๊ฐฑ์‹ ํ•˜๊ณ  1์„ ๋ฐ˜ํ™˜ํ•œ๋‹ค. ์‹คํŒจํ•˜๋ฉด ๊ฐฑ์‹ ํ•˜์ง€ ์•Š๊ณ  0์„ ๋ฐ˜ํ™˜ํ•œ๋‹ค.

void lock(lock_t *lock) {
while (1) {
	while (LoadLinked(&lockโˆ’>flag) == 1)
	; // 0์ด ๋  ๋•Œ๊นŒ์ง€ spin
	if (StoreConditional(&lockโˆ’>flag, 1) == 1)
		return; // 1๋กœ ๋ณ€๊ฒฝํ•˜๋Š” ๊ฒƒ์„ ์„ฑ๊ณตํ•œ ๊ฒฝ์šฐ ์™„๋ฃŒ
		// ์•„๋‹ˆ๋ผ๋ฉด ์ฒ˜์Œ๋ถ€ํ„ฐ ๋‹ค์‹œ ์‹œ๋„
	}
}

void unlock(lock_t *lock) {
	lockโˆ’>flag = 0;
}

์“ฐ๋ ˆ๋“œ๊ฐ€ while๋ฌธ์„ ๋Œ๋ฉฐ flag๊ฐ€ 0์ด ๋˜๊ธฐ๋ฅผ ๊ธฐ๋‹ค๋ฆฐ๋‹ค. 0์ด ๋˜๋ฉด ๋ฝ์ด ํ•ด์ œ๋œ ๊ฒƒ์ด๋‹ค. ๋ฝ์ด ํš๋“ ๊ฐ€๋Šฅ ์ƒํƒœ๊ฐ€ ๋˜๋ฉด ์“ฐ๋ ˆ๋“œ๋Š” StoredConditional ๋ช…๋ น์–ด๋กœ ๋ฝ ํš๋“์„ ์‹œ๋„ํ•˜๊ณ  ์„ฑ๊ณตํ•œ๋‹ค๋ฉด flag ๊ฐ’์„ 1๋กœ ๋ณ€๊ฒฝํ•˜๊ณ , ์ž„๊ณ„ ์˜์—ญ์œผ๋กœ ์ง„์ž…ํ•œ๋‹ค.

StoredConditional ์ด ์‹คํŒจํ•  ์ˆ˜๋„ ์žˆ๋‹ค. ์ด ์ ์ด ์ค‘์š”ํ•˜๋‹ค.

  1. ์“ฐ๋ ˆ๋“œ๊ฐ€ lock()์„ ํ˜ธ์ถœํ•˜์—ฌ LoadLinked๋ฅผ ์‹คํ–‰. ๋ฝ์ด ์‚ฌ์šฉ ๊ฐ€๋Šฅํ•œ ์ƒํƒœ์ด๋ฏ€๋กœ 0์„ ๋ฐ˜ํ™˜. ๋ฃจํ”„ ํƒˆ์ถœ
  2. StoredConditional ๋ช…๋ น์–ด๋ฅผ ์‹œ๋„ํ•˜๊ธฐ ์ „์— ์ธํ„ฐ๋ŸฝํŠธ
  3. ๋‹ค๋ฅธ ์“ฐ๋ ˆ๋“œ๊ฐ€ lock()์„ ํ˜ธ์ถœ. LoadLinked๋ฅผ ์‹คํ–‰. ๋ฝ์ด ์‚ฌ์šฉ ๊ฐ€๋Šฅํ•œ ์ƒํƒœ์ด๋ฏ€๋กœ 0์„ ๋ฐ˜ํ™˜. ๋ฃจํ”„ ํƒˆ์ถœ
  4. ์ด ์‹œ์ ์— ๋‘ ์“ฐ๋ ˆ๋“œ๋Š” ๋ชจ๋‘ LoadLinked ๋ช…๋ น์–ด๋ฅผ ์‹คํ–‰ํ•˜์˜€๊ณ  ๊ฐ์ž๊ฐ€ StoredConditional์„ ํ˜ธ์ถœํ•˜๋ ค๋Š” ์ƒํ™ฉ

์ด ๋ช…๋ น์–ด์˜ ์ฃผ์š” ๊ธฐ๋Šฅ์€ ์˜ค์ง ํ•˜๋‚˜์˜ ์“ฐ๋ ˆ๋“œ๋งŒ flag๊ฐ’์„ 1๋กœ ์„ค์ •ํ•œ ํ›„์— ๋ฝ์„ ํš๋“ํ•  ์ˆ˜ ์žˆ๋„๋ก ํ•˜๋Š” ๊ฒƒ์ด๋‹ค. ๋‘ ๋ฒˆ์งธ๋กœ StoredConditional์„ ์‹คํ–‰ํ•œ ์“ฐ๋ ˆ๋“œ๋Š” ๋ฝ ํš๋“์— ์‹คํŒจํ•˜๊ณ  ๋‹ค์Œ ๊ธฐํšŒ๋ฅผ ๊ธฐ๋‹ค๋ ค์•ผ ํ•œ๋‹ค.

์ด๋ ‡๊ฒŒ ์“ฐ๋ฉด ๋” ์งง์•„์ง„๋‹ค.

void lock(lock_t *lock) {
	while (LoadLinked(&lockโˆ’>flag)||!StoreConditional(&lockโˆ’>flag, 1))
	; // spin
}

11. Fetch-And-Add

๋งˆ์ง€๋ง‰ ํ•˜๋“œ์›จ์–ด ๊ธฐ๋ฒ•์€ Fetch-And-Add ๋ช…๋ น์–ด๋กœ, ์›์ž์ ์œผ๋กœ ํŠน์ • ์ฃผ์†Œ์˜ ์˜ˆ์ „ ๊ฐ’์„ ๋ฐ˜ํ™˜ํ•˜๋ฉด์„œ ๊ฐ’์„ ์ฆ๊ฐ€์‹œํ‚จ๋‹ค.

int FetchAndAdd(int *ptr) {
	int old = *ptr;
	*ptr = old + 1;
	return old;
}

FetchAndAdd ๋ช…๋ น์–ด๋ฅผ ์‚ฌ์šฉํ•˜์—ฌ ํ‹ฐ์ผ“ ๋ฝ ์ด๋ผ๋Š” ์žฌ๋ฏธ์žˆ๋Š” ๊ฒƒ์„ ๋งŒ๋“ค์–ด๋ณด์ž!

typedef struct __lock_t {
	int ticket;
	int turn;
} lock_t;

void lock_init(lock_t *lock) {
	lockโˆ’>ticket = 0;
	lockโˆ’>turn = 0;
}

void lock(lock_t *lock) {
	int myturn = FetchAndAdd(&lockโˆ’>ticket);
	while (lockโˆ’>turn != myturn)
	; // spin
}

void unlock(lock_t *lock) {
	FetchAndAdd(&lockโˆ’>turn);
}

ticket๊ณผ turn ์กฐํ•ฉ์„ ์‚ฌ์šฉํ•ด ๋ฝ์„ ๋งŒ๋“ ๋‹ค. ํ•˜๋‚˜์˜ ์“ฐ๋ ˆ๋“œ๊ฐ€ ๋ฝ ํš๋“์„ ์›ํ•˜๋ฉด, ticket ๋ณ€์ˆ˜์— atomic ์—ฐ์‚ฐ์ธ FetchAndAdd ๋ช…๋ น์–ด๋ฅผ ์‹คํ–‰ํ•œ๋‹ค. ๊ฒฐ๊ณผ ๊ฐ’์€ ํ•ด๋‹น ์“ฐ๋ ˆ๋“œ์˜ ์ฐจ๋ก€๋ฅผ ๋‚˜ํƒ€๋‚ธ๋‹ค.

์ „์—ญ ๊ณต์œ  ๋ณ€์ˆ˜์ธ lock->turn์„ ์‚ฌ์šฉํ•˜์—ฌ ์–ด๋А ์“ฐ๋ ˆ๋“œ์˜ ์ฐจ๋ก€์ธ์ง€ ํŒ๋‹จํ•œ๋‹ค. ๋งŒ์•ฝ ํ•œ ์“ฐ๋ ˆ๋“œ๊ฐ€ myturn == lock->turn์กฐ๊ฑด์— ๋ถ€ํ•ฉํ•˜๋ฉด, while ๋ฌธ์„ ๋ฒ—์–ด๋‚˜ ๋ฝ์„ ํš๋“ํ•œ๋‹ค. unlock()์€ turn ๋ณ€์ˆ˜์˜ ๊ฐ’์„ ์ฆ๊ฐ€์‹œ์ผœ์„œ ๋Œ€๊ธฐ ์ค‘์ธ ๋‹ค์Œ ์“ฐ๋ ˆ๋“œ์—๊ฒŒ ์ž„๊ณ„ ์˜์—ญ ์ง„์ž… ์ฐจ๋ก€๋ฅผ ๋„˜๊ฒจ ์ค€๋‹ค.

์ด์ „๊นŒ์ง€ ์ ‘๊ทผ ๋ฐฉ๋ฒ•๊ณผ์˜ ๊ฐ€์žฅ ์ค‘์š”ํ•œ ์ฐจ์ด์ ์€ ๋ชจ๋“  ์“ฐ๋ ˆ๋“œ๋“ค์ด ๊ฐ์ž์˜ ์ˆœ์„œ์— ๋”ฐ๋ผ ์ง„ํ–‰ํ•œ๋‹ค๋Š” ๊ฒƒ์ด๋‹ค. ์“ฐ๋ ˆ๋“œ๊ฐ€ ํ‹ฐ์ผ“ ๊ฐ’์„ ํ• ๋‹น๋ฐ›์•˜๋‹ค๋ฉด, ๋ฏธ๋ž˜์˜ ์–ด๋А ์‹œ์ ์— ์‹คํ–‰๋˜๊ธฐ ์œ„ํ•ด ์Šค์ผ€์ค„๋˜์–ด ์žˆ๋‹ค๋Š” ๊ฒƒ์ด๋‹ค. ์ด์ „๊นŒ์ง€๋Š” ์ด๋Ÿฌํ•œ ๋ณด์žฅ์ด ์—†์—ˆ๋‹ค. ์˜ˆ๋ฅผ ๋“ค์–ด Test-And-Set์˜ ๊ฒฝ์šฐ ๋‹ค๋ฅธ ์“ฐ๋ ˆ๋“œ๋“ค์€ ๋ฝ์„ ํš๋“/ํ•ด์ œํ•˜๋”๋ผ๋„ ์–ด๋–ค ์“ฐ๋ ˆ๋“œ๋Š” ๊ณ„์† ํšŒ์ „๋งŒ ํ•˜๊ณ  ์žˆ์„ ์ˆ˜ ์žˆ๋‹ค. ์ฆ‰ ์ด๋ฒˆ ํ•ด๋ฒ•์€ ๊ณต์ •์„ฑ์ด ์žˆ๋‹ค.

12. ์š”์•ฝ: ๊ณผ๋„ํ•œ ์Šคํ•€

์ง€๊ธˆ๊นŒ์ง€ ๋‹ค๋ฃฌ ํ•ด๋ฒ•์ด ํšจ์œจ์ ์ด์ง€ ์•Š์€ ๊ฒฝ์šฐ๋„ ์žˆ๋‹ค. ํŠนํžˆ ํ”„๋กœ์„ธ์„œ๊ฐ€ ํ•˜๋‚˜์ธ ๊ฒฝ์šฐ ๋น„ํšจ์œจ์ ์ด๋‹ค. NN๊ฐœ์˜ ์“ฐ๋ ˆ๋“œ๊ฐ€ ํ•˜๋‚˜์˜ ๋ฝ์„ ํš๋“ํ•˜๊ธฐ ์œ„ํ•ด ๊ฒฝ์Ÿํ•˜๊ฒŒ ๋œ๋‹ค๋ฉด? Nโˆ’1N-1๊ฐœ์˜ ์“ฐ๋ ˆ๋“œ๊ฐ€ ๊ณ„์† spinํ•  ๊ฒƒ์ด๋‹ค.

์–ด๋–ป๊ฒŒ ํ•˜๋ฉด ์Šคํ•€์— CPU์‹œ๊ฐ„์„ ๋‚ญ๋น„ํ•˜์ง€ ์•Š๋Š” ๋ฝ์„ ๋งŒ๋“ค ์ˆ˜ ์žˆ์„๊นŒ?

13. ๊ฐ„๋‹จํ•œ ์ ‘๊ทผ๋ฒ•: ๋ฌด์กฐ๊ฑด ์–‘๋ณด!

ํ•˜๋“œ์›จ์–ด์˜ ์ง€์›์„ ๋ฐ›์•„ ๋งŽ์€ ๊ฒƒ์„ ํ•ด๊ฒฐํ•˜์˜€๋‹ค. ๋™์ž‘์ด ๊ฒ€์ฆ๋œ ๋ฝ๊ณผ ๋ฝ ํš๋“์˜ ๊ณต์ •์„ฑ๊นŒ์ง€๋„ ํ•ด๊ฒฐํ–ˆ๋‹ค. ํ•˜์ง€๋งŒ ์Šคํ•€๋งŒ ๋ฌดํ•œํžˆ ํ•˜๋Š” ๊ฒฝ์šฐ๋Š” ์–ด๋–ป๊ฒŒ ํ•ด๊ฒฐํ•ด์•ผ ํ• ๊นŒ?

์ฒซ ๋ฒˆ์งธ๋กœ, ๋ฝ์ด ํ•ด์ œ๋˜๊ธฐ๋ฅผ ๊ธฐ๋‹ค๋ฆฌ๋ฉฐ ์Šคํ•€ํ•ด์•ผ ํ•˜๋Š” ๊ฒฝ์šฐ ์ž์‹ ์—๊ฒŒ ํ• ๋‹น๋œ CPU๋ฅผ ๋‹ค๋ฅธ ์“ฐ๋ ˆ๋“œ์—๊ฒŒ ์–‘๋ณดํ•˜๋„๋ก ํ•  ์ˆ˜ ์žˆ๋‹ค.

void init() {
	flag = 0;
}

void lock() {
	while (TestAndSet(&flag, 1) == 1)
		yield(); // CPU ์–‘๋ณด
}

void unlock() {
	flag = 0;
}

์šด์˜์ฒด์ œ์— ์ž์‹ ์ด ํ• ๋‹น๋ฐ›์€ CPU ์‹œ๊ฐ„์„ ํฌ๊ธฐํ•˜๊ณ  ๋‹ค๋ฅธ ์“ฐ๋ ˆ๋“œ๊ฐ€ ์‹คํ–‰๋  ์ˆ˜ ์žˆ๋„๋ก ํ•˜๋Š” yield() ๊ธฐ๋ฒ•์ด ์žˆ๋‹ค๊ณ  ๊ฐ€์ •ํ•œ๋‹ค. ํ•˜๋‚˜์˜ ์“ฐ๋ ˆ๋“œ๋Š” running, ready, blocked ์„ธ ๊ฐ€์ง€ ์ƒํƒœ๊ฐ€ ์žˆ๋‹ค. yield ๋ผ๋Š” ์‹œ์Šคํ…œ ์ฝœ์€ ํ˜ธ์ถœ ์“ฐ๋ ˆ๋“œ ์ƒํƒœ๋ฅผ running์—์„œ ready๋กœ ๋ณ€ํ™˜ํ•˜์—ฌ ๋‹ค๋ฅธ ์“ฐ๋ ˆ๋“œ๊ฐ€ running ์ƒํƒœ๋กœ ์ „์ดํ•˜๋„๋ก ํ•œ๋‹ค.

๋‹จ์ผ CPU ์‹œ์Šคํ…œ์—์„œ ๋‘ ๊ฐœ์˜ ์“ฐ๋ ˆ๋“œ๋ฅผ ์‹คํ–‰ํ•˜๋Š” ๊ฒฝ์šฐ, ์ ์ ˆํ•˜๊ฒŒ ๋™์ž‘ํ•˜๋Š” ๊ฒƒ์„ ์•Œ ์ˆ˜ ์žˆ๋‹ค. (๊ณ„์† ์–‘๋ณด)

100๊ฐœ ์ •๋„์˜ ์“ฐ๋ ˆ๋“œ๋“ค์ด ๋ฝ์„ ํš๋“ํ•˜๊ธฐ ์œ„ํ•ด ๊ฒฝ์Ÿํ•˜๋Š” ๊ฒฝ์šฐ๋ฅผ ์‚ดํŽด๋ณด์ž. ํ•œ ์“ฐ๋ ˆ๋“œ๊ฐ€ ๋ฝ์„ ํš๋“ํ•˜๋ฉด ๋‚˜๋จธ์ง€ 99๊ฐœ์˜ ์“ฐ๋ ˆ๋“œ๊ฐ€ ๊ฐ์ž lock()์„ ํ˜ธ์ถœํ•˜๊ณ  CPU๋ฅผ ์–‘๋ณดํ•œ๋‹ค. ๋ผ์šด๋“œ ๋กœ๋นˆ ๊ธฐ๋ฒ•์„ ์‚ฌ์šฉํ•˜๋Š” ๊ฒฝ์šฐ, ๋ฝ์„ ๊ฐ–๊ณ  ์žˆ๋Š” ์“ฐ๋ ˆ๋“œ๊ฐ€ ๋‹ค์‹œ ์‹คํ–‰๋˜๊ธฐ๊นŒ์ง€ 99๊ฐœ์˜ ์“ฐ๋ ˆ๋“œ๊ฐ€ ์‹คํ–‰ํ•˜๊ณ  ์–‘๋ณดํ•˜๋Š” ํŒจํ„ด์œผ๋กœ ๋™์ž‘ํ•˜๋Š”๋ฐ, ์ด๋Š” ๋น„์šฉ์ด ๋งŒ๋งŒ์น˜ ์•Š๊ฒŒ ๋“ ๋‹ค.

๋˜, ๊ตถ์ฃผ๋ฆผ ๋ฌธ์ œ๋„ ํ•ด๊ฒฐํ•˜์ง€ ๋ชปํ–ˆ๋‹ค. ์–ด๋–ค ์“ฐ๋ ˆ๋“œ๋Š” ๋ฌดํ•œํžˆ ์–‘๋ณด๋งŒ ํ•˜๊ฒŒ ๋ ์ง€๋„ ๋ชจ๋ฅธ๋‹ค.

14. ํ์˜ ์‚ฌ์šฉ: ์Šคํ•€ ๋Œ€์‹  ์ž ์ž๊ธฐ

์ด์ „ ๋ฐฉ๋ฒ•๋“ค์€ ๋„ˆ๋ฌด ๋งŽ์€ ๋ถ€๋ถ„์„ ์šด์— ๋งก๊ฒผ๋‹ค. ์Šค์ผ€์ค„๋Ÿฌ๊ฐ€ ์ข‹์ง€ ์•Š์€ ์„ ํƒ์„ ํ•œ๋‹ค๋ฉด ๊ธฐ๋‹ค๋ฆฌ๊ฑฐ๋‚˜ CPU๋ฅผ ์–‘๋ณดํ•ด์•ผ ํ•œ๋‹ค. ๋‘˜ ๋‹ค ๋‚ญ๋น„์˜ ์—ฌ์ง€๊ฐ€ ์žˆ๊ณ  ์“ฐ๋ ˆ๋“œ๊ฐ€ ๊ตถ์ฃผ๋ฆด ์ˆ˜ ์žˆ๋‹ค.

์–ด๋–ค ์“ฐ๋ ˆ๋“œ๊ฐ€ ๋‹ค์Œ์œผ๋กœ ๋ฝ์„ ํš๋“ํ• ์ง€๋ฅผ ๋ช…์‹œ์ ์œผ๋กœ ์ œ์–ดํ•  ์ˆ˜ ์žˆ์–ด์•ผ ํ•œ๋‹ค. ์ด๋ฅผ ์œ„ํ•ด ์šด์˜์ฒด์ œ๋กœ๋ถ€ํ„ฐ ์ ์ ˆํ•œ ์ง€์›์„ ๋ฐ›๊ณ , ํ๋ฅผ ์ด์šฉํ•œ ๋Œ€๊ธฐ ์“ฐ๋ ˆ๋“œ๋“ค์„ ๊ด€๋ฆฌํ•  ๊ฒƒ์ด๋‹ค.

๊ฐ„๋‹จํžˆ Solaris์˜ ๋ฐฉ์‹์œผ๋กœ ํ•ด๋ณด์ž.

park(): ํ˜ธ์ถœํ•˜๋Š” ์“ฐ๋ ˆ๋“œ๋ฅผ ์ž ์žฌ์šฐ๋Š” ํ•จ์ˆ˜ unpark(threadID): threadID๋กœ ๋ช…์‹œ๋œ ํŠน์ • ์“ฐ๋ ˆ๋“œ๋ฅผ ๊นจ์šฐ๋Š” ํ•จ์ˆ˜

์ด ๋‘ ๋ฃจํ‹ด์€ ์ด๋ฏธ ์‚ฌ์šฉ ์ค‘์ธ ๋ฝ์„ ์š”์ฒญํ•˜๋Š” ํ”„๋กœ์„ธ์Šค๋ฅผ ์žฌ์šฐ๊ณ  ํ•ด๋‹น ๋ฝ์ด ํ•ด์ œ๋˜๋ฉด ๊นจ์šฐ๋„๋ก ํ•˜๋Š” ๋ฝ์„ ์ œ์ž‘ํ•˜๋Š” ๋ฐ ์•ž๋’ค๋กœ ์‚ฌ์šฉํ•  ์ˆ˜ ์žˆ๋‹ค.

TestAndSet ๊ฐœ๋…์„ ๋ฝ ๋Œ€๊ธฐ์ž ์ „์šฉ ํ์™€ ํ•จ๊ป˜ ์‚ฌ์šฉํ•˜์—ฌ ํšจ์œจ์ ์ธ ๋ฝ์„ ๋งŒ๋“ค ๊ฒƒ์ด๊ณ , ํ๋ฅผ ์‚ฌ์šฉํ•˜์—ฌ ๊ตถ์ฃผ๋ฆผ ํ˜„์ƒ์„ ๋ฐฉ์ง€ํ•  ๊ฒƒ์ด๋‹ค.

typedef struct __lock_t {
	int flag;
	int guard;
	queue_t *q;
} lock_t;

void lock_init(lock_t *m) {
	mโˆ’>flag = 0;
	mโˆ’>guard = 0;
	queue_init(mโˆ’>q);
}

void lock(lock_t *m) {
	while (TestAndSet(&mโˆ’>guard, 1) == 1)
	; // ํšŒ์ „ํ•˜๋ฉด์„œ guard ๋ฝ์„ ํš๋“
	if (mโˆ’>flag == 0) {
		mโˆ’>flag = 1; // ๋ฝ ํš๋“
		mโˆ’>guard = 0;
	} else {
		queue_add(mโˆ’>q, gettid());
		mโˆ’>guard = 0;
		park(); // ์ž ์žฌ์šฐ๊ธฐ
	}
}

void unlock(lock_t *m) {
	while (TestAndSet(&mโˆ’>guard, 1) == 1)
	; // ํšŒ์ „ํ•˜๋ฉด์„œ guard ๋ฝ์„ ํš๋“
	if (queue_empty(mโˆ’>q))
		mโˆ’>flag = 0; // ๋ฝ์„ ํฌ๊ธฐํ•จ. ๋ˆ„๊ตฌ๋„ ๋ฝ์„ ์›์น˜ ์•Š์Œ.
	else
		unpark(queue_remove(mโˆ’>q)); // ๋ฝ์„ ํš๋“ํ•จ (๋‹ค์Œ ์“ฐ๋ ˆ๋“œ๋ฅผ ์œ„ํ•ด)
	mโˆ’>guard = 0;
}

guard ๋ณ€์ˆ˜๋ฅผ ์‚ฌ์šฉํ•˜์—ฌ flag์™€ ํ์˜ ์‚ฝ์ž…๊ณผ ์‚ญ์ œ ๋™์ž‘์„ ์Šคํ•€ ๋ฝ์œผ๋กœ ๋ณดํ˜ธํ•œ๋‹ค. ์ด ๋ฐฉ๋ฒ•์€ ์Šคํ•€์„ ์™„์ „ํžˆ ๋ฐฐ์ œํ•˜์ง€๋Š” ๋ชปํ–ˆ๋‹ค. ํ•˜์ง€๋งŒ ์Šคํ•€ ๋Œ€๊ธฐ ์‹œ๊ฐ„์€ ๊ฝค ์งง๋‹ค. ์‚ฌ์šฉ์ž๊ฐ€ ์ง€์ •ํ•œ ์ž„๊ณ„ ์˜์—ญ์— ์ง„์ž…ํ•˜๋Š” ๊ฒƒ์ด ์•„๋‹ˆ๋ผ ๋ฝ๊ณผ ์–ธ๋ฝ ์ฝ”๋“œ ๋‚ด์˜ ๋ช‡ ๊ฐœ์˜ ๋ช…๋ น์–ด๋งŒ ์ˆ˜ํ–‰ํ•˜๋ฉด ๋˜๊ธฐ ๋•Œ๋ฌธ์ด๋‹ค.

lock() ์— ์ถ”๊ฐ€๋œ ๋™์ž‘์ด ์žˆ๋‹ค. lock()์„ ํ˜ธ์ถœํ–ˆ๋Š”๋ฐ ๋‹ค๋ฅธ ์“ฐ๋ ˆ๋“œ๊ฐ€ ์ด๋ฏธ ๋ฝ์„ ๋ณด์œ ์ค‘์ด๋ผ๋ฉด, gettid()๋ฅผ ํ˜ธ์ถœํ•˜์—ฌ ํ˜„์žฌ ์‹คํ–‰ ์ค‘์ธ ์“ฐ๋ ˆ๋“œ ID๋ฅผ ์–ป๊ณ , ๋ฝ ์†Œ์œ ์ž์˜ ํ์— ์ž๊ธฐ ์ž์‹ ์„ ์ถ”๊ฐ€ํ•˜๊ณ  guard ๋ณ€์ˆ˜๋ฅผ 0์œผ๋กœ ๋ณ€๊ฒฝํ•œ ํ›„ CPU๋ฅผ ์–‘๋ณดํ•œ๋‹ค.

๋‹ค๋ฅธ ์“ฐ๋ ˆ๋“œ๊ฐ€ ๊นจ์–ด๋‚ฌ์„ ๋•Œ flag ๋ณ€์ˆ˜๊ฐ€ 0์œผ๋กœ ์„ค์ •๋˜์ง€ ์•Š๋Š”๋‹ค. ๊นจ์–ด๋‚  ๋•Œ๋Š” guard ๋ฝ์„ ํš๋“ํ•œ ์ƒํƒœ๊ฐ€ ์•„๋‹ˆ๊ธฐ ๋•Œ๋ฌธ์— flag๋ฅผ 1๋กœ ๋ณ€๊ฒฝํ•  ์ˆ˜ ์—†๋‹ค. ๋”ฐ๋ผ์„œ ๊ทธ๋ƒฅ 1์ธ ์ฑ„๋กœ ๋‘๊ณ  ๋ฝ์„ ํš๋“ํ•˜๋ ค๋Š” ๋‹ค์Œ ์“ฐ๋ ˆ๋“œ๋กœ ์ง์ ‘ ์ „๋‹ฌํ•œ๋‹ค. flag๋Š” 0์ด ๋˜์—ˆ๋‹ค ๋‹ค์‹œ 1์ด ๋˜๋Š”๊ฒŒ ์•„๋‹ˆ๋ผ ๊ทธ๋ƒฅ ๊ณ„์† 1์ด๋‹ค.

๋งˆ์ง€๋ง‰์œผ๋กœ, park() ์ง์ „์— ๊ฒฝ์Ÿ ์กฐ๊ฑด์ด ๋ฐœ์ƒํ•œ๋‹ค. ํ•œ ์“ฐ๋ ˆ๋“œ๋Š” ๋ฝ์ด ์‚ฌ์šฉ์ค‘์ด๋ผ park()๋ฅผ ์‹คํ–‰ํ•˜๋ ค๊ณ  ํ•œ๋‹ค. ๊ทธ ์ง์ „์— ๋ฝ ์†Œ์œ ์žํ•œํ…Œ CPU๊ฐ€ ํ• ๋‹น๋˜๋ฉด ๋ฌธ์ œ๊ฐ€ ์ƒ๊ธธ ์ˆ˜ ์žˆ๋‹ค.

๊ฒฝ์Ÿ ์กฐ๊ฑด์ด ์–ด๋–ป๊ฒŒ ๋ฐœ์ƒํ•˜๋Š”๊ฐ€?

  1. B๊ฐ€ park()๋ฅผ ํ˜ธ์ถœํ•˜๊ธฐ ๋ฐ”๋กœ ์ง์ „์— CPU ์Šค์ผ€์ค„๋ง์ด ๋ฐœ์ƒํ•˜์—ฌ A๊ฐ€ ์‹คํ–‰๋œ๋‹ค.
  2. A๊ฐ€ ๋ฝ์„ ํ•ด์ œํ•˜๊ณ  B๋ฅผ ๊นจ์šฐ๊ธฐ ์œ„ํ•ด unpark()๋ฅผ ํ˜ธ์ถœํ•œ๋‹ค.
  3. ํ•˜์ง€๋งŒ B๋Š” ์•„์ง park()๋ฅผ ํ˜ธ์ถœํ•˜์ง€ ์•Š์•˜์œผ๋ฏ€๋กœ, ์‹ค์ œ๋กœ๋Š” ๊นจ์›Œ์งˆ ์ˆ˜ ์—†๋‹ค. ๋”ฐ๋ผ์„œ B๋Š” ๋ฝ์ด ํ•ด์ œ๋˜์—ˆ์Œ์—๋„ ๋ถˆ๊ตฌํ•˜๊ณ  ๊ณ„์† ๋Œ€๊ธฐ ์ƒํƒœ์— ๋จธ๋ฌผ๊ฒŒ ๋œ๋‹ค.

์ด๋Ÿฌํ•œ ๋ฌธ์ œ๋ฅผ ํ•ด๊ฒฐํ•˜๊ธฐ ์œ„ํ•ด Solaris ์šด์˜์ฒด์ œ๋Š” setpark() ์‹œ์Šคํ…œ ์ฝœ์„ ๋„์ž…ํ–ˆ๋‹ค.

setpark()๋Š” ์–ด๋–ป๊ฒŒ ๋™์ž‘ํ•˜๋Š”๊ฐ€?

setpark()๋Š” ์“ฐ๋ ˆ๋“œ๊ฐ€ โ€œ์ด์ œ ๊ณง park()๋ฅผ ํ˜ธ์ถœํ•  ๊ฒƒ์ด๋‹คโ€๋ผ๊ณ  ์‹œ์Šคํ…œ์— ์•Œ๋ฆฌ๋Š” ์—ญํ• ์„ ํ•œ๋‹ค. ์ด๋ ‡๊ฒŒ ํ•˜๋ฉด, ๋งŒ์•ฝ setpark() ํ˜ธ์ถœ ํ›„์— ๋ฝ์ด ํ•ด์ œ๋˜์–ด unpark()๊ฐ€ ํ˜ธ์ถœ๋˜๋ฉด, ์‹œ์Šคํ…œ์€ ์ด ์ •๋ณด๋ฅผ ์บ์‹œ์— ์ €์žฅํ•œ๋‹ค. ๋”ฐ๋ผ์„œ ์‹ค์ œ park()๊ฐ€ ํ˜ธ์ถœ๋  ๋•Œ, ์“ฐ๋ ˆ๋“œ๋Š” ์ž ๋“ค์ง€ ์•Š๊ณ  ๋ฐ”๋กœ ๊นจ์–ด๋‚˜๊ฒŒ ๋œ๋‹ค. ์ด๋Ÿฐ ๋ฐฉ์‹์œผ๋กœ setpark()๋Š” ๋ฝ์„ ํ•ด์ œํ•˜๊ณ  ๋‚˜์„œ ์“ฐ๋ ˆ๋“œ๋ฅผ ๊นจ์šฐ๋Š” ๋™์ž‘ ์‚ฌ์ด์—์„œ ๋ฐœ์ƒํ•  ์ˆ˜ ์žˆ๋Š” ๊ฒฝ์Ÿ ์กฐ๊ฑด์„ ํ•ด๊ฒฐํ•œ๋‹ค.

guard ๋ณ€์ˆ˜์˜ ์—ญํ• ์„ ์ปค๋„์—์„œ ๋‹ด๋‹นํ•˜๋Š” ๊ฒƒ๋„ ํ•˜๋‚˜์˜ ๋ฐฉ๋ฒ•์ด๋‹ค. ์ปค๋„์€ ๋ฝ ํ•ด์ œ์™€ ์‹คํ–‰ ์ค‘์ธ ์“ฐ๋ ˆ๋“œ๋ฅผ ํ์—์„œ ์ œ๊ฑฐํ•˜๋Š” ๋™์ž‘์„ atomicํ•˜๊ฒŒ ์ฒ˜๋ฆฌํ•˜๊ธฐ ์œ„ํ•ด ์ฃผ์˜๋ฅผ ๊ธฐ์šธ์—ฌ์•ผ ํ•œ๋‹ค.

15. ๋‹ค๋ฅธ ์šด์˜์ฒด์ œ, ๋‹ค๋ฅธ ์ง€์›

Linux์˜ ๊ฒฝ์šฐ futex๋ผ๋Š” ๊ฒƒ์„ ์ง€์›ํ•œ๋‹ค. ๊ฐ futex๋Š” ํŠน์ • ๋ฌผ๋ฆฌ ๋ฉ”๋ชจ๋ฆฌ ์ฃผ์†Œ์™€ ์—ฐ๊ฑธ์ด ๋˜์–ด ์žˆ์œผ๋ฉฐ futex๋งˆ๋‹ค ์ปค๋„ ๋‚ด๋ถ€์˜ ํ๋ฅผ ๊ฐ€์ง€๊ณ  ์žˆ๋‹ค. ํ˜ธ์ถœ์ž๋Š” futex๋ฅผ ํ˜ธ์ถœํ•˜์—ฌ ํ•„์š”์— ๋”ฐ๋ผ ์ž ์„ ์ž๊ฑฐ๋‚˜ ๊นจ์–ด๋‚  ์ˆ˜ ์žˆ๋‹ค.

void mutex_lock (int *mutex) {
	int v;
	
	if (atomic_bit_test_set (mutex, 31) == 0)
		return;
	atomic_increment (mutex);
	while (1) {
	if (atomic_bit_test_set (mutex, 31) == 0) {
		atomic_decrement (mutex);
		return;
	}

	v = *mutex;
	if (v >= 0)
		continue;
	futex_wait (mutex, v);
	}
}

void mutex_unlock (int *mutex) {

	if (atomic_add_zero (mutex๋‚ฌ 0x80000000))
		return;
	
	futex_wake (mutex);

16. 2๋‹จ๊ณ„ ๋ฝ

2๋‹จ๊ณ„ ๋ฝ ๊ธฐ๋ฒ•์€ ๋ฝ์ด ๊ณง ํ•ด์ œ๋  ๊ฒƒ ๊ฐ™์€ ๊ฒฝ์šฐ๋ผ๋ฉด ํšŒ์ „ ๋Œ€๊ธฐ๊ฐ€ ์œ ์šฉํ•  ์ˆ˜ ์žˆ๋‹ค๋Š” ๊ฒƒ์—์„œ ์ฐฉ์•ˆํ•˜์˜€๋‹ค.

  1. ํšŒ์ „ ๋‹จ๊ณ„(Spinning Phase): ๋ฝ์„ ๊ณง ํš๋“ํ•  ์ˆ˜ ์žˆ์„ ๊ฒƒ์ด๋ผ๋Š” ๊ธฐ๋Œ€ํ•˜์—, ์“ฐ๋ ˆ๋“œ๋Š” โ€œํšŒ์ „โ€ ํ•˜๋ฉด์„œ ๋Œ€๊ธฐํ•œ๋‹ค. ์ฆ‰, ์“ฐ๋ ˆ๋“œ๋Š” ์ผ์ • ์‹œ๊ฐ„ ๋™์•ˆ ๋ฃจํ”„๋ฅผ ๋Œ๋ฉด์„œ ๋ฝ์˜ ์ƒํƒœ๋ฅผ ํ™•์ธํ•˜๊ณ , ๊ฐ€๋Šฅํ•˜๋ฉด ๋ฝ์„ ํš๋“ํ•˜๋ ค๊ณ  ์‹œ๋„ํ•œ๋‹ค.
  2. ์ž ๊น€ ๋‹จ๊ณ„(Sleeping Phase): ์ฒซ ๋‹จ๊ณ„์—์„œ ๋ฝ์„ ์–ป์ง€ ๋ชปํ•œ ๊ฒฝ์šฐ, ์ด์ œ๋Š” ์“ฐ๋ ˆ๋“œ๊ฐ€ ์ž ์— ๋“ค์–ด์„œ ๋ฝ์ด ํ•ด์ œ๋  ๋•Œ๊นŒ์ง€ ๊ธฐ๋‹ค๋ฆฐ๋‹ค. ๋ฝ์ด ํ•ด์ œ๋˜๋ฉด ์“ฐ๋ ˆ๋“œ๋Š” ๊นจ์–ด๋‚˜์„œ ์ž‘์—…์„ ๊ณ„์†ํ•ฉ๋‹ˆ๋‹ค.

์•ž์„œ ๋ณธ Linux์˜ ๋ฝ์€ ์ด๋Ÿฌํ•œ ํ˜•ํƒœ๋ฅผ ๋ฐ–๋Š” ๋ฝ์ด์ง€๋งŒ ํ•œ ๋ฒˆ๋งŒ ํšŒ์ „ํ•œ๋‹ค. ์ผ๋ฐ˜ํ™”๋œ ๋ฐฉ๋ฒ•์€ futex๊ฐ€ ์ž ์žฌ์šฐ๊ธฐ ์ „์— ์ผ์ • ์‹œ๊ฐ„ ๋™์•ˆ ๋ฐ˜๋ณต๋ฌธ ๋‚ด์—์„œ ํšŒ์ „ํ•˜๋„๋ก ํ•˜๋Š” ๊ฒƒ์ด๋‹ค. 2 ๋‹จ๊ณ„ ๋ฝ์€ ๋‘ ๊ฐœ์˜ ์ข‹์€ ๊ฐœ๋…์„ ์‚ฌ์šฉํ•˜์—ฌ ๊ฐœ์„ ๋œ ํ•˜๋‚˜๋ฅผ ๋งŒ๋“ค์–ด ๋‚ด๋Š” ํ•˜์ด๋ธŒ๋ฆฌ๋“œ ๋ฐฉ์‹์˜ ์ผ์ข…์ด๋‹ค.

๋œฌ๊ธˆ์—†์ง€๋งŒ ์ฑ… ์ถ”์ฒœ

๋™์‹œ์„ฑ ํ”„๋กœ๊ทธ๋ž˜๋ฐ - Rust, C, ์–ด์…ˆ๋ธ”๋ฆฌ์–ด๋กœ ๊ตฌํ˜„ํ•˜๋ฉฐ ๋ฐฐ์šฐ๋Š” ๋™์‹œ์„ฑ ํ”„๋กœ๊ทธ๋ž˜๋ฐ A to Z