์ฌ๋ฌ ๊ฐ์ ๋ช ๋ น์ด๋ค์ 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();
}
์ด ๋ฐฉ๋ฒ์ ์ฅ์ ์ ๋จ์ํ๋ค๋ ๊ฒ์ด๊ณ , ๋จ์ ์ ๋ง๋ค.
- ๋จผ์ , ์ด ์์ฒญ์ ํ๋ ์ฐ๋ ๋๊ฐ ์ธํฐ๋ฝํธ๋ฅผ ํ์ฑํ/๋นํ์ฑํ ํ๋ ์ปค๋ ๋ชจ๋ ํน๊ถ ์ฐ์ฐ์ ์คํํ ์ ์๋๋ก ํ๊ฐํด์ผ ํ๋ค. ๋ง์ฝ ์ด๋ค ํ๋ก๊ทธ๋จ์ด ์์๊ณผ ๋์์
lock()์ ํธ์ถํ๊ณ ๋ฌดํ ๋ฐ๋ณต๋ฌธ์ ๋ค์ด๊ฐ๋ค๋ฉด, ์ด์์ฒด์ ๋ ์์คํ ์ ์ ์ด๊ถ์ ๋ค์ ์ป์ ์ ์๋ค. - ๋, ๋ฉํฐํ๋ก์ธ์์์๋ ์ ์ฉ์ ํ ์ ์๋ค. ์ฌ๋ฌ ์ฐ๋ ๋๊ฐ ์ฌ๋ฌ CPU์์ ์คํ ์ค์ด๋ผ๋ฉด, ๊ฐ ์ฐ๋ ๋๊ฐ ๋์ผํ ์๊ณ ์์ญ์ ์ง์ ํ๋ ค๊ณ ํ ์ ์๋ค. ์ด ๋ ์ธํฐ๋ฝํธ๋ฅผ ๋นํ์ฑํํ๋ ๊ฒ์ ๋ค๋ฅธ ํ๋ก์ธ์์์ ์คํ์ค์ธ ํ๋ก๊ทธ๋จ์๋ ์ ํ ์ํฅ์ ์ฃผ์ง ์๋๋ค. ์ฆ, ์๊ณ ์์ญ์ ์ง์ ํ๋ ๊ฒ์ ๋ง์ ์ ์๋ค.
- ์ฅ์๊ฐ ์ธํฐ๋ฝํธ๋ฅผ ์ค์ง์ํค๋ ๊ฒ์ ์ค์ํ ์ธํฐ๋ฝํธ ์์ ์ ๋์น๊ฒ ํ ์ ์๋ค. CPU๊ฐ ์ ์ฅ ์ฅ์น์์ ์ฝ๊ธฐ ์์ฒญ์ ๋ง์น ์ฌ์ค์ ๋ชจ๋ฅด๊ณ ์ง๋๊ฐ๋ค๊ณ ํด๋ณด์. ์ด์์ฒด์ ๋ ์ฝ๊ธฐ ๊ฒฐ๊ณผ๋ฅผ ๊ธฐ๋ค๋ฆฌ๋ ํ๋ก์ธ์ค๋ฅผ ๊นจ์ธ ์ ์์ ๊ฒ์ด๋ค.
- ๋ง์ง๋ง์ผ๋ก, ๋นํจ์จ์ ์ด๋ค. ์ผ๋ฐ์ ์ธ ๋ช ๋ น์ด์ ๋นํด ์ธํฐ๋ฝํธ๋ฅผ ๋นํ์ฑํ์ํค๋ ์ฝ๋๋ค์ ์ต์ 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๋ก ์ค์ ํ๊ณ ์๊ณ ์์ญ ๋ด๋ก ์ง์
ํ๋ค.
์ด ์ฝ๋์๋ ๋ ๊ฐ์ง ๋ฌธ์ ๊ฐ ์๋ค.
์ ํ์ฑ

์์ํ ๋ 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์ ๊ฒฝ์ฐ ์คํ ๋ฝ์ด ๊ฐ๋ ์ฑ๋ฅ ์ค๋ฒํค๋๋ ์๋นํ ํด ์ ์๋ค. ๊ฐ ์ค ๊ฐ์ ๋ค๋ฅธ ์ฐ๋ ๋๊ฐ ๋ฝ์ ํ๋ํ๋ ค๊ณ ํ ๋, ์ค์ผ์ค๋ฌ๊ฐ ์ด๋ค์ ํ ๋ฒ์ฉ ๊นจ์ธ ์๋ ์๋ค. 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 ์ด ์คํจํ ์๋ ์๋ค. ์ด ์ ์ด ์ค์ํ๋ค.
- ์ฐ๋ ๋๊ฐ
lock()์ ํธ์ถํ์ฌLoadLinked๋ฅผ ์คํ. ๋ฝ์ด ์ฌ์ฉ ๊ฐ๋ฅํ ์ํ์ด๋ฏ๋ก 0์ ๋ฐํ. ๋ฃจํ ํ์ถ StoredConditional๋ช ๋ น์ด๋ฅผ ์๋ํ๊ธฐ ์ ์ ์ธํฐ๋ฝํธ- ๋ค๋ฅธ ์ฐ๋ ๋๊ฐ
lock()์ ํธ์ถ.LoadLinked๋ฅผ ์คํ. ๋ฝ์ด ์ฌ์ฉ ๊ฐ๋ฅํ ์ํ์ด๋ฏ๋ก 0์ ๋ฐํ. ๋ฃจํ ํ์ถ - ์ด ์์ ์ ๋ ์ฐ๋ ๋๋ ๋ชจ๋
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. ์์ฝ: ๊ณผ๋ํ ์คํ
์ง๊ธ๊น์ง ๋ค๋ฃฌ ํด๋ฒ์ด ํจ์จ์ ์ด์ง ์์ ๊ฒฝ์ฐ๋ ์๋ค. ํนํ ํ๋ก์ธ์๊ฐ ํ๋์ธ ๊ฒฝ์ฐ ๋นํจ์จ์ ์ด๋ค.
๊ฐ์ ์ฐ๋ ๋๊ฐ ํ๋์ ๋ฝ์ ํ๋ํ๊ธฐ ์ํด ๊ฒฝ์ํ๊ฒ ๋๋ค๋ฉด? ๊ฐ์ ์ฐ๋ ๋๊ฐ ๊ณ์ 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๊ฐ ํ ๋น๋๋ฉด ๋ฌธ์ ๊ฐ ์๊ธธ ์ ์๋ค.
๊ฒฝ์ ์กฐ๊ฑด์ด ์ด๋ป๊ฒ ๋ฐ์ํ๋๊ฐ?
- B๊ฐ
park()๋ฅผ ํธ์ถํ๊ธฐ ๋ฐ๋ก ์ง์ ์ CPU ์ค์ผ์ค๋ง์ด ๋ฐ์ํ์ฌ A๊ฐ ์คํ๋๋ค. - A๊ฐ ๋ฝ์ ํด์ ํ๊ณ B๋ฅผ ๊นจ์ฐ๊ธฐ ์ํด
unpark()๋ฅผ ํธ์ถํ๋ค. - ํ์ง๋ง 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๋จ๊ณ ๋ฝ ๊ธฐ๋ฒ์ ๋ฝ์ด ๊ณง ํด์ ๋ ๊ฒ ๊ฐ์ ๊ฒฝ์ฐ๋ผ๋ฉด ํ์ ๋๊ธฐ๊ฐ ์ ์ฉํ ์ ์๋ค๋ ๊ฒ์์ ์ฐฉ์ํ์๋ค.
- ํ์ ๋จ๊ณ(Spinning Phase): ๋ฝ์ ๊ณง ํ๋ํ ์ ์์ ๊ฒ์ด๋ผ๋ ๊ธฐ๋ํ์, ์ฐ๋ ๋๋ โํ์ โ ํ๋ฉด์ ๋๊ธฐํ๋ค. ์ฆ, ์ฐ๋ ๋๋ ์ผ์ ์๊ฐ ๋์ ๋ฃจํ๋ฅผ ๋๋ฉด์ ๋ฝ์ ์ํ๋ฅผ ํ์ธํ๊ณ , ๊ฐ๋ฅํ๋ฉด ๋ฝ์ ํ๋ํ๋ ค๊ณ ์๋ํ๋ค.
- ์ ๊น ๋จ๊ณ(Sleeping Phase): ์ฒซ ๋จ๊ณ์์ ๋ฝ์ ์ป์ง ๋ชปํ ๊ฒฝ์ฐ, ์ด์ ๋ ์ฐ๋ ๋๊ฐ ์ ์ ๋ค์ด์ ๋ฝ์ด ํด์ ๋ ๋๊น์ง ๊ธฐ๋ค๋ฆฐ๋ค. ๋ฝ์ด ํด์ ๋๋ฉด ์ฐ๋ ๋๋ ๊นจ์ด๋์ ์์ ์ ๊ณ์ํฉ๋๋ค.
์์ ๋ณธ Linux์ ๋ฝ์ ์ด๋ฌํ ํํ๋ฅผ ๋ฐ๋ ๋ฝ์ด์ง๋ง ํ ๋ฒ๋ง ํ์ ํ๋ค. ์ผ๋ฐํ๋ ๋ฐฉ๋ฒ์ futex๊ฐ ์ ์ฌ์ฐ๊ธฐ ์ ์ ์ผ์ ์๊ฐ ๋์ ๋ฐ๋ณต๋ฌธ ๋ด์์ ํ์ ํ๋๋ก ํ๋ ๊ฒ์ด๋ค. 2 ๋จ๊ณ ๋ฝ์ ๋ ๊ฐ์ ์ข์ ๊ฐ๋
์ ์ฌ์ฉํ์ฌ ๊ฐ์ ๋ ํ๋๋ฅผ ๋ง๋ค์ด ๋ด๋ ํ์ด๋ธ๋ฆฌ๋ ๋ฐฉ์์ ์ผ์ข
์ด๋ค.