[OS] Operating System(6-1): Critical section, peterson, Synchronization Hardware
๐ ์ด์์ฒด์ ์ ๊ณต ์์ ์ ๋ฆฌ
ํ๋ก์ธ์ค๋ค์ด ๋์์ ์คํ๋๋ฉด์ ์๊ธฐ๋ ๋ฌธ์ ๊ฐ ์๋ค
์ฌ๋ฌ ํ๋ก์ธ์ค๊ฐ ๊ณต์ ๋ฐ์ดํฐ์ ์ ๊ทผํ ๋ ๋ฐ์ดํฐ ๋ถ์ผ์น ๋ฌธ์ ๊ฐ ๋ฐ์ํ๋ค
๊ทธ๋์ ๋ฐ์ดํฐ์ ์ผ๊ด์ฑ์ ์ํด์๋ olderly execution์ ๋ณด์ฅํ๋ ๋ฉ์ปค๋์ฆ์ด ํ์
์ด์ ๋ํ ์์๋ก Producer-Consumer Problem
์ด ์๋ค
Producer-Consumer Problem
Producer
: ๋ฐ์ดํฐ๋ฅผ ์์ฐํด์ ๋ฒํผ์ ์ ์ฅConsumer
: ๋ฒํผ์์ ๋ฐ์ดํฐ๋ฅผ ๊ฐ์ ธ์ ์ฌ์ฉ- ๋ฒํผ๋ ํ์ ๋ ํฌ๊ธฐ, ๊ฐ๋ ์ฐผ์ ๋ ์์ฐ์๋ ๋๊ธฐํด์ผํ๊ณ , ๋น์ด์์ ๋ ์๋น์๋ ๋๊ธฐ
counter
๋ณ์: ํ์ฌ ๋ฒํผ์ ์๋ ์์ดํ ์ ์๋ฅผ ์ถ์
Producer code
1
2
3
4
5
6
7
8
9
10
while (true) {
/* produce an item in next_produced */
while (counter == BUFFER_SIZE)
; /* do nothing */ // "busy waiting"
buffer[in] = next_produced;
in = (in + 1) % BUFFER_SIZE;
counter++;
}
- ์์ฐ์๋ ๋ฒํผ๊ฐ ๊ฐ๋ ์ฐผ๋์ง ํ์ธํ๊ณ (counter == BUFFER_SIZE), ๊ฐ๋ ์ฐผ๋ค๋ฉด ๋๊ธฐ
- ๊ณต๊ฐ์ด ์์ผ๋ฉด ์์ดํ ์ ๋ฒํผ์ ์ถ๊ฐํ๊ณ , in ํฌ์ธํฐ๋ฅผ ๋ค์ ์์น๋ก ์ด๋
Consumer code
1
2
3
4
5
6
7
8
9
10
while (true) {
while (counter == 0)
; /* do nothing */ // "busy waiting"
next_consumed = buffer[out];
out = (out + 1) % BUFFER_SIZE;
counter--;
/* consume the item in next_consumed */
}
Race Condition
๐Race Condition: ๋ ๊ฐ ์ด์์ ํ๋ก์ธ์ค๊ฐ ๋์์ ๊ณต์ ๋ฐ์ดํฐ์ ์ ๊ทผํ๋ ค๊ณ ํ ๋, ์ ๊ทผ ์์์ ๋ฐ๋ผ ์คํ ๊ฒฐ๊ณผ๊ฐ ๋ฌ๋ผ์ง ์ ์๋ ์ํฉ
โ ์ด๋ก ์ธํด ๋ฐ์ดํฐ ๋ถ์ผ์น ๋ฐ์!
counter ์์
counter++
์ counter--
๋ ์ค์ ๋ก ์์์ ์ด์ง ์๋ค. ๊ธฐ๊ณ์ด๋ก ๋ฒ์ญํ๋ฉด ๋ค์๊ณผ ๊ฐ๋ค.
counter++
:
1
2
3
load: register1 = counter
inc: register1 = register1 + 1
store: counter = register1
counter--
:
1
2
3
load: register2 = counter
dec: register2 = register2 - 1
store: counter = register2
์ ์๊ฒฐ๊ณผ๋ 5์ด์ด์ผํจ
ํ์ง๋ง ์ด ๋ ๋ช ๋ น์ด๋ ๋์์ ์คํ๋๊ธฐ ๋๋ฌธ์ ๋ฐ์ดํฐ ๋ถ์ผ์น๊ฐ ๋ฐ์!
fork() ์์
- ํ๋ก์ธ์ค P0, P1์ด
fork()
๋ก ์์ ํ๋ก์ธ์ค๋ฅผ ์์ฑํ์ ๋, ๋์์ ํธ์ถํ๊ฒ ๋๋ฉด ๋์ผํ PID๋ฅผ ๋ฐ๊ฒ ๋๋ค - ์ด๋ ๋์ผํ PID๊ฐ ๋ ๊ฐ์ ์๋ก ๋ค๋ฅธ ํ๋ก์ธ์ค์ ํ ๋น๋๋ ๋ฌธ์ ๋ฅผ ๋ฐ์ํ๋ค.
- ์ด๋ฌํ ๋ฌธ์ ๋ mutual exclusion(์ํธ๋ฐฐ์ )์ด ํ์ํ๋ค
Critical Section
๐Critical Section: ์ฌ๋ฌ ํ๋ก์ธ์ค๊ฐ ๊ณต์ ํ๋ ๋ฐ์ดํฐ๋ ์์์ ์ ๊ทผํ๋ ์ฝ๋ ์์ญ(์ ๊ทผ๋ง์ด ์๋๋ผ ์ฌ์ฉํด์ผํจ)
- ์ด ์์ญ์์๋ ํ ๋ฒ์ ํ๋์ ํ๋ก์ธ์ค๋ง ์คํ๋จ
Critial Section
์์ ํ๋ก์ธ์ค๋ ๊ณต์ ๋ณ์ ๋ณ๊ฒฝ, ํ ์ด๋ธ ์ ๋ฐ์ดํธ, ํ์ผ ์ฐ๊ธฐ ๋ฑ์ ์์ ์ ์ํ
โ ํ๋ก์ธ์ค์ ์ผ๋ฐ์ ์ธ ๊ตฌ์กฐ:
1
2
3
4
5
6
do {
entry section // ์ง์
์์ญ
critical section // ์๊ณ ์์ญ
exit section // ํด์ถ ์์ญ
remainder section // ๋๋จธ์ง ์์ญ
} while (true);
entry section
: critical section์ ๋ค์ด๊ฐ๊ธฐ ์ํ ํ๊ฐ๋ฅผ ์์ฒญํ๋ ๋ถ๋ถcritical section
: ๊ณต์ ์์์ ์ ๊ทผํ๋ ๋ถ๋ถexit section
: ์๊ณ์์ญ ๋ฒ์ด๋ ๋ ์คํ๋๋ ๋ถ๋ถremainder section
: ๊ทธ ์ธ ๋๋จธ์ง ์ฝ๋ ๋ถ๋ถ
Critical Section solution
- Mutual Exclusion
- ํ ํ๋ก์ธ์ค๊ฐ ์๊ณ์์ญ์์ ์คํ ์ค์ด๋ฉด, ๋ค๋ฅธ ์ด๋ค ํ๋ก์ธ์ค๋ ์๊ณ์์ญ์์ ์คํ X
- Progress
- ์๊ณ์์ญ์์ ์คํ ์ค์ธ ํ๋ก์ธ์ค๊ฐ ์๊ณ , ๋ช๋ช ํ๋ก์ธ์ค๋ค์ด ์๊ณ์์ญ์ ๋ค์ด๊ฐ๊ธธ ์ํ๋ค๋ฉด, ๋ค์์ ์ด๋ค ํ๋ก์ธ์ค๊ฐ ์๊ณ์์ญ์ ๋ค์ด๊ฐ์ง ๊ฒฐ์ ํ๋ ๊ฒ์ด ๋ฌดํ์ ์ฐ๊ธฐ๋์ด์๋ ์ ๋๊ฒ๋ ํด์ผํจ
- Bounded Waiting
- ํ๋ก์ธ์ค๊ฐ ์๊ณ์์ญ์ ๋ค์ด๊ฐ๊ธฐ ์ํ ์์ฒญ์ ํ ํ, ๊ทธ ์์ฒญ์ด ํ์ฉ๋๊ธฐ ์ ์ ๋ค๋ฅธ ํ๋ก์ธ์ค๋ค์ด ์๊ณ์์ญ์ ๋ค์ด๊ฐ ์ ์๋ ํ์์ ํ๊ณ๊ฐ ์์ด์ผํจ
- starvation(๊ธฐ์ ํ์)์ ๋ฐฉ์งํ๊ธฐ ์ํจ
Critical Section Handling in OS
์ด์์ฒด์ ์์ ์๊ณ์์ญ์ ์ฒ๋ฆฌํ๋ ๋ฐฉ๋ฒ์ ์ปค๋์ด ์ ์ ํ(preemptive)์ธ์ง ๋น์ ์ ํ(non-preemptive)์ธ์ง์ ๋ฐ๋ผ ๋ค๋ฅด๋ค.
- Preemptive Kernel
- ํ๋ก์ธ์ค๊ฐ ์ปค๋ ๋ชจ๋์์ ์คํ ์ค์ผ ๋๋ ํ๋ก์ธ์ค๋ฅผ preemptive ๊ฐ๋ฅ
- ์ฆ, ๋์ ์ฐ์ ์์์ ํ๋ก์ธ์ค๊ฐ ํ์ฌ ์คํ ์ค์ธ ํ๋ก์ธ์ค๋ฅผ ์ค๋จ์ํค๊ณ CPU๋ฅผ ์ฐจ์งํ ์ ์๋ค
- ๋จ์ : SMP(Symmetric Multi-Processing) ์ํคํ ์ฒ์์ ์ค๊ณํ๊ธฐ ์ด๋ ต๋ค
- Non-preemptive Kernel
- ํ๋ก์ธ์ค๊ฐ ์ปค๋ ๋ชจ๋๋ฅผ ๋น ์ ธ๋๊ฐ๊ฑฐ๋, ๋ธ๋ก ๋๋ ์๋ฐ์ ์ผ๋ก CPU๋ฅผ ์๋ณดํ ๋๊น์ง ์คํ ๋๋ค.
- ์ปค๋ ๋ชจ๋์์ ์ค์ง์ ์ธ race condition์ด ์๋ค.
- ๋จ์ : ์ค์๊ฐ ํ๋ก๊ทธ๋๋ฐ์ ์ ํฉํ์ง ์์
๋จ์ผ ์ฝ์ด ์์คํ
์์๋ interrupt disabling
์ ์ฌ์ฉํด์ critical section์ ๋ณดํธํ ์ ์๋ค.
โ ํ์ง๋ง ๋ค์ค์ฝ์ด/ํ๋ก์ธ์ค
์์๋ ํจ์จ์ฑ์ด ๋จ์ด์ ธ์ ์ฐ์ง ์๋๋ค.
- ๊ทธ๋์ preemptive kernel์ ์ ํธ!!
Petersonโs Solution
๐Petersonโs Solution: ์๊ณ์์ญ ๋ฌธ์ ๋ฅผ ํด๊ฒฐํ๋ ๋ํ์ ์ธ ์๊ณ ๋ฆฌ์ฆ
- ํ๋ ์ํคํ ์ฒ์์๋ ๋ณ๋ก์ด์ง๋ง, ์๊ณ ๋ฆฌ์ฆ์ ์ ๊ทผ๋ฒ์ผ๋ก๋ ํ๋ฅญํจ
โ ์ฃผ์ ํน์ง:
- ๋ ๊ฐ ํ๋ก์ธ์ค๋ฅผ ๋์
- ๊ธฐ๊ณ์ด
load
,store
๋ช ๋ น์ด atomic์ด๋ผ๊ณ ๊ฐ์ - atomic: ๋ฐ๋์ง ์๋ ์ฑ์ง
- ๋ ๊ฐ์ ํ๋ก์ธ์ค๋ ๋ ๊ฐ์ ๋ณ์๋ฅผ ๊ณต์ :
int turn
: ์ด๋ค ํ๋ก์ธ์ค์ ์ฐจ๋ก์ธ์งboolean flag[2]
: ๊ฐ ํ๋ก์ธ์ค๊ฐ ์๊ณ์์ญ์ ๋ค์ด๊ฐ ์ค๋น๊ฐ ๋์๋์ง
โ ์๊ณ ๋ฆฌ์ฆ ๊ตฌํ:
1
2
3
4
5
6
7
8
9
10
11
12
while (true) {
flag[i] = true; // ๋ ์๊ณ์์ญ์ ๋ค์ด๊ฐ ์ค๋น๊ฐ ๋์ด
turn = j; // ์๋๋ฐฉ์๊ฒ ์ฐจ๋ก๋ฅผ ์๋ณดํด
while (flag[j] && turn == j)
; // ์๋๋ฐฉ์ด ์ค๋น๋์ด ์๊ณ , ์๋๋ฐฉ ์ฐจ๋ก๋ฉด ๋๊ธฐ
/* critical section */ // ์๊ณ์์ญ
flag[i] = false; // ์๊ณ์์ญ ์ฌ์ฉ ์๋ฃ
/* remainder section */ // ๋๋จธ์ง ์์ญ
}
flag[i]=true
๋ก ์ค์ ํด์ ์๊ณ์์ญ์ ๋ค์ด๊ฐ๊ณ ์ถ๋ค๊ณ ํ์turn
๋ณ์๋ฅผ ์๋๋ฐฉ ํ๋ก์ธ์ค ๋ฒํธj
๋ก ์ค์ ํ์ฌ โ์๋ณดโ- ์ดํ ์๋๋ฐฉ์ ํ๋๊ทธ
flag[j] == true
์ด๊ณturn==j
์ด๋ฉด ๋๊ธฐ - ์๊ณ์์ญ์ ์คํํ ํ์๋ ์์ ์ ํ๋๊ทธ
flag[i] == false
๋ก ์ค์ ํ์ฌ ์๊ณ์์ญ ์ฌ์ฉ์ด ๋๋ฌ์์ ํ์
ํ๋ ์ํคํ ์ณ์์๋ ์ ๋๋ก ์๋X
ํ๋ก์ธ์๋ ์ปดํ์ผ๋ฌ๋ ์ฑ๋ฅํฅ์์ ์ํด ์์กด์ฑ ์๋ ์ฐ์ฐ๋ค์ ์์๋ฅผ ์ฌ๋ฐฐ์นํจ
โ instruction reordering ๋ฌธ์ ๋ฐ์ ๋จ์ผ์ค๋ ๋์์๋ ๊ด์ฐฎ์ง๋ง ๋ค์ค์ค๋ ๋์์ ๋ฌธ์ ๋ฐ์
instruction reordering ์์
1
2
flag[i] = true;
turn = j;
ํผํฐ์จ ์๊ณ ๋ฆฌ์ฆ์ ์์ ๊ฐ์ ์ฝ๋๊ฐ ์กด์ฌ ์ปดํ์ผ๋ฌ๋ ํ๋ก์ธ์๊ฐ ๋ ๋ช ๋ น์ด์ ์์๋ฅผ ๋ฐ๊พธ๋ฉด:
1
2
turn = j;
flag[i] = true;
์ด๋ ๊ฒ ๋๋ฉด ๋ค์๊ณผ ๊ฐ์ ์ํฉ์ด ๋ฐ์ํ ์ ์๋ค
- ํ๋ก์ธ์ค P0:
turn = 1
์คํ ํflag[0] = true
์คํ - ํ๋ก์ธ์ค P1:
turn = 0
์คํ ํflag[1] = true
์คํ
๊ฒฐ๊ณผ์ ์ผ๋ก flag[0] = true, flag[1] = true, turn = 0
์ด ๋์ด P0๋ while ์กฐ๊ฑด์ ํต๊ณผํ๊ณ , P1๋ turn = 0์ด๋ฏ๋ก while ์กฐ๊ฑด์ ํต๊ณผํจ ์ฆ, ๋ ํ๋ก์ธ์ค๊ฐ ๋์์ critical section์ ์ง์
ํ๋ ์ํธ ๋ฐฐ์ ์๋ฐ์ด ๋ฐ์
Synchronization Hardware
๊ทธ๋ผ software์ธก๋ฉด์์์ cs๋ฌธ์ ํด๊ฒฐ ๋ฐฉ์๋ง๊ณ hardware์ ํด๊ฒฐ์ฑ ์ ์์๋ณด์
CS๋ฌธ์ ๋ฅผ ํด๊ฒฐํ๊ธฐ์ํด ํ๋ ์ปดํจํฐ๋ ๋ค์ํ ํ๋์จ์ด ๋๊ธฐํ ๊ธฐ๋ฒ์ ์ ๊ณตํจ
โ ๊ทธ ์ด์ - uniprocessors ์์คํ ์ ํ๊ณ
- ๋จ์ผ ํ๋ก์ธ์ ์์คํ ์์๋ disable interrupts ๋ฐฉ์์ผ๋ก cs๋ฅผ ๋ณดํธํ ์ ์๋ค.
- ํ์ฌ ์คํ ์ค์ธ ์ฝ๋๋ preemption ์์ด ์คํ๋จ
- ํ์ง๋ง ์ด ๋ฐฉ์์ ๋ค์ค ํ๋ก์ธ์ ์์คํ ์์๋ ๋นํจ์จ์ !
- ๋ํ ํ์ฅ์ฑ(scalability)์ด ๋จ์ด์ง
ํ๋์จ์ด ์ง์์ 3๊ฐ์ง ํํ:
- Memory barriers
- Hardware instructions
- Atomic variables
Memory Barriers
๐Memory Barriers: ๋ค์ค ํ๋ก์ธ์ ํ๊ฒฝ์์ ๋ฉ๋ชจ๋ฆฌ ์ฐ์ฐ์ ์์๋ฅผ ๋ณด์ฅํ๊ธฐ ์ํ ๋ฉ์ปค๋์ฆ
Memory Model
- Memory Model: ์ปดํจํฐ ์ํคํ ์ฒ๊ฐ ์์ฉ ํ๋ก๊ทธ๋จ์ ์ ๊ณตํ๋ ๋ฉ๋ชจ๋ฆฌ ๋ณด์ฅ(memory guarantees)์ ์๋ฏธ
โ Memory model์ 2๊ฐ์ง๋ก ๋๋จ:
- Strongly ordered: ํ ํ๋ก์ธ์ค์์ ๊ฐ ๋ณ๊ฒฝ์ด ์๋ฃ๋ ๋ ๋ค๋ฅธ ํ๋ก์ธ์์ ์ฆ์ ๋ณด์
- Wekly ordered: ๊ฐ ๋ณ๊ฒฝ์ด ์๋ฃ๋๊ธฐ ์ ์๋ผ๋ ํ์ฌ ์ํ๋ฅผ ๋ณด์ฌ์ค, ์ฆ ๋ฐ๋ก ๋ณด์ด์ง ์์ ์๋ ์์
- Memory barrier: ๋ฉ๋ชจ๋ฆฌ์ ๋ณ๊ฒฝ์ฌํญ์ด ๋ชจ๋ ํ๋ก์ธ์์ ์ ํ(propagated)๋๋๋ก ๊ฐ์ ํ๋ ๋ช
๋ น์ด(=memory fence)
- ํ์ฌ ์งํ ์ค์ธ load์ store๊ฐ ์๋ฃ๋ ํ์ ์๋ก์ด load์ store๊ฐ ์ํ๋๋๋ก ํจ
- memory barrier ํ์ฉ ์์
1
2
3
4
5
6
7
8
9
10
11
12
13
// ๊ณต์ ๋ฐ์ดํฐ
boolean flag = false;
int x = 0;
// ์ค๋ ๋ 1
while (!flag)
memory_barrier(); // x ๊ฐ์ด ๋ก๋ฉ๋๊ธฐ ์ ์ flag ๊ฐ์ด ๋ก๋ฉ๋๋ ๊ฒ์ ๋ณด์ฅ
print x;
// ์ค๋ ๋ 2
x = 100;
memory_barrier(); // x = 100์ด flag = true๋ณด๋ค ๋จผ์ ์๋ฃ๋๋ ๊ฒ์ ๋ณด์ฅ
flag = true;
- memory_barrier๋ โx ๊ฐ์ด ๋ก๋ฉ๋๊ธฐ ์ ์ flag ๊ฐ์ด ๋ก๋ฉ๋๋ ๊ฒ์ ๋ณด์ฅโ
x = 100
์ดflag = true
๋ณด๋ค ๋จผ์ ์๋ฃ๋๋ ๊ฒ์ ๋ณด์ฅ- Memory barrier๋ very low-level operation์ผ๋ก ์ปค๋ ๊ฐ๋ฐ์๊ฐ mutual exclusion ์ฝ๋๋ฅผ ํน๋ณํ ์์ฑํ ๋๋ง ์ฌ์ฉ
Hardware Instruction
๐Hardware Instruction: cs๋ฌธ์ ๋ฅผ ํด๊ฒฐํ๊ธฐ ์ํ special hardware instructions
โ ํน์ง:
- ์์์ ์คํ ๋ณด์ฅ: ๋ช ๋ น์ด๊ฐ ์คํ๋๋ ๋์ ์ธํฐ๋ฝํธ ๋ถ๊ฐ(uninterrupt)
- ์๋ ๋ด์ฉ์ ํ ์คํธํ๊ณ ์์ ํ๊ฑฐ๋, ๋ด์ฉ ๊ตํ ๊ฐ๋ฅ(test,modify,swap)
- ํ๋ ํ๋ก์ธ์์์ ๋๋ฆฌ ์ง์๋จ
๋ํ์ ์ผ๋ก 3๊ฐ์ง ๋ช ๋ น์ด๊ฐ ์กด์ฌ:
- Test-and-Set instruction
- Compare-and-Swap instruction
- Compare-and-Exchange instruction
Test-and-Set instruction
- Test-and-Set instruction: ๋ณ์์ ๊ฐ์ ํ ์คํธํ๊ณ ์ค์ ํ๋ ์ฐ์ฐ์ ์์์ ์ผ๋ก ์ํ
1
2
3
4
5
boolean test_and_set(boolean *target) {
boolean rv = *target;
*target = true; //target์ TRUE๋ก ์ค์
return rv; // ์ค์ ์ target๊ฐ์ return
}
โ ํน์ง:
- ์์์ ์ผ๋ก(atomically) ์คํ๋จ
- ์ ๋ฌ๋ ๋งค๊ฐ๋ณ์์ ์๋ ๊ฐ์ return
- ๋งค๊ฐ๋ณ์์ ๊ฐ์ true๋ก ์ค์
Test-and-Set์ ์ด์ฉํ critical section ํด๊ฒฐ์ฑ
1
2
3
4
5
6
7
8
9
10
11
// ๊ณต์ boolean ๋ณ์ lock, ์ด๊ธฐ๊ฐ์ false
do {
while (test_and_set(&lock)) //spin lock
; /* ๋ฐ์ ๋๊ธฐ (busy waiting) */
/* critical section */
lock = false;
/* remainder section */
} while (true);
test_and_set(&lock)
: lock์ ํ์ฌ ๊ฐ์ return, lock์ true๋ก ์ค์ - return๊ฐ์ด true: ๋ค๋ฅธ ํ๋ก์ธ์ค๊ฐ ์ด๋ฏธ cs์์ญ์ ์๋ค๋ ์๋ฏธ โ ๋๊ธฐํจ
- return๊ฐ์ด false: CS์ ์๋ฌด๋ ์๋ค๋ ์๋ฏธ, lock์ ์ด๋ฏธ TRUE๋ก ๋ง๋ค์๊ธฐ ๋๋ฌธ์ ๋ค๋ฅธ ํ๋ก์ธ์ค๊ฐ CS์ ๋ค์ด์ค์ง ๋ชปํจ. ๋ฐ๋ผ์ ์์ ์ด CS์ ๋ค์ด๊ฐ
- cs๋ฅผ ๋น ์ ธ๋์ฌ ๋ lock์ false๋ก ์ค์ โ ๋ค๋ฅธ ํ๋ก์ธ์ค cs ์ง์ ๊ฐ๋ฅ
์ด ๋ฐฉ์์ ์คํ ๋ฝ(spin lock)์ด๋ผ๊ณ ๋ ๋ถ๋ฆฌ๋ฉฐ, ํ๋ก์ธ์ค๊ฐ ๋ฝ์ ํ๋ํ ๋๊น์ง ๊ณ์ CPU๋ฅผ ์ฌ์ฉํ๋ฉฐ ๋๊ธฐํ๊ธฐ ๋๋ฌธ์ CPU ์์์ ๋ญ๋นํ ์ ์์
Compare-and-Swap instruction
- Compare-and-Swap instruction: ๋ฉ๋ชจ๋ฆฌ ์์น์ ๋ด์ฉ๊ณผ ์ฃผ์ด์ง ๊ฐ์ ๋น๊ตํ๊ณ , ๊ฐ์ผ๋ฉด ์ ๊ฐ์ผ๋ก ๊ต์ฒด
1 2 3 4 5 6
int compare_and_swap(int *value, int expected, int new_value) { int temp = *value; if (*value == expected) *value = new_value; return temp; }
โ ํน์ง:
- ์์์ ์ผ๋ก(atomically) ์คํ๋จ
- value ๋งค๊ฐ๋ณ์์ ์๋ ๊ฐ์ return
- value๊ฐ expected ๊ฐ๊ณผ ๊ฐ์ ๋๋ง value๋ฅผ new_value๋ก ์ค์
Compare-and-Swap์ ์ด์ฉํ critical section ํด๊ฒฐ์ฑ :
1
2
3
4
5
6
7
8
9
10
11
// ๊ณต์ int ๋ณ์ lock, ์ด๊ธฐ๊ฐ์ 0
while (true) {
while (compare_and_swap(&lock, 0, 1) != 0) //spin lock
; /* ๋ฐ์ ๋๊ธฐ (busy waiting) */
/* critical section */
lock = 0;
/* remainder section */
}
compare_and_swap(&lock, 0, 1)
: lock์ ๊ฐ์ด 0์ด๋ฉด 1๋ก ๋ณ๊ฒฝํ๊ณ ์๋ ๊ฐ(0)์ ๋ฐํ- lock์ ๊ฐ์ด 0์ด ์๋๋ฉด ๊ฐ์ ๋ณ๊ฒฝํ์ง ์๊ณ ํ์ฌ ๊ฐ(1)์ ๋ฐํ
- ๋ฐํ๊ฐ์ด 0์ด ์๋๋ฉด ๋ค๋ฅธ ํ๋ก์ธ์ค๊ฐ ์ด๋ฏธ ์๊ณ์์ญ์ ์์ผ๋ฏ๋ก ๋๊ธฐ
- ๋ฐํ๊ฐ์ด 0์ด๋ฉด ์๊ณ์์ญ์ ๋ค์ด๊ฐ
Compare-and-Exchange intruction
Compare-and-Exchange instruction : Compare-and-Swap์ ํ์ฅ๋ ๋ฒ์ , ๊ฐ์ด ์ผ์นํ์ง ์์ ๊ฒฝ์ฐ ์์ ๊ฐ์ ์ ๋ฐ์ดํธ
1
2
3
4
5
6
7
8
9
bool compare_and_exchange(int *value, int *expected, int new_value) {
if (*value == *expected) {
*value = new_value;
return true;
} else {
*expected = *value;
return false;
}
}
โ ํน์ง:
- ์์์ ์ผ๋ก(atomically) ์คํ๋จ
- value๊ฐ expected ๊ฐ๊ณผ ๊ฐ์ผ๋ฉด value๋ฅผ new_value๋ก ์ค์ ํ๊ณ true ๋ฐํ
- ์ผ์นํ์ง ์์ผ๋ฉด expected๋ฅผ value์ ์ค์ ๊ฐ์ผ๋ก ์ ๋ฐ์ดํธํ๊ณ false ๋ฐํ
Compare-and-Exchange๋ฅผ ์ด์ฉํ ์๊ณ์์ญ ํด๊ฒฐ์ฑ
1
2
3
4
5
6
7
8
9
10
11
12
// ๊ณต์ int ๋ณ์ lock, ์ด๊ธฐ๊ฐ์ 0
while (true) {
expected = 0;
while (!compare_and_exchange(&lock, &expected, 1)) //spin lock
expected = 0;
/* critical section */
lock = 0;
/* remainder section */
}
์์ ์๊ณ ๋ฆฌ์ฆ๋ค์ starvation์ ๋ฐฉ์ง ๋ชปํ ์๋ ์๋ค!!
์ด๋ฅผ ํด๊ฒฐํ๊ธฐ ์ํด Compare-and-Swap์ ์ฌ์ฉํด์ bounded-waiting์ ๋ณด์ฅํ๋ ์๊ณ ๋ฆฌ์ฆ์ด ์๋ค.
Bounded-waiting Mutual Exclusion with CAS
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
while (true) {
waiting[i] = true;
key = 1;
while (waiting[i] && key == 1)
key = compare_and_swap(&lock, 0, 1);
waiting[i] = false;
/* critical section */
j = (i + 1) % n;
while ((j != i) && !waiting[j])
j = (j + 1) % n;
if (j == i) // ์๋ฌด๋ ๊ธฐ๋ค๋ฆฌ๋ ํ๋ก์ธ์ค๊ฐ ์๋ค๋ ๋ป
lock = 0; // lock์ ํผ๋ค
else
//cs์ ๋ค์ด๊ฐ๊ธฐ๋ฅผ ๊ธฐ๋ค๋ฆฌ๋ ํ๋ก์ธ์ค๊ฐ ์์ด์ lock์ ๊ฑด ์ํ์์ ๋ค์ด๊ฐ๋๋ก ํจ
waiting[j] = false;
/* remainder section */
}
waiting[i] = true
: ํ๋ก์ธ์ค i๊ฐ ์๊ณ์์ญ์ ๋ค์ด๊ฐ๊ธฐ๋ฅผ ๊ธฐ๋ค๋ฆฌ๊ณ ์์์ ํ์key = compare_and_swap(&lock, 0, 1)
์ ํตํด lock์ ํ๋ํ๋ ค๊ณ ์๋key=1
: lock์ด ๊ฑธ๋ ค์์(๋๊ตฐ๊ฐ cs์ ์์)key=0
: cs์ง์ ๊ฐ๋ฅ
- ์๊ณ์์ญ์ ๋์ฌ ๋, ๋๊ธฐ ์ค์ธ ๋ค์ ํ๋ก์ธ์ค๋ฅผ ์ฐพ์ waiting ์ํ๋ฅผ false๋ก ๋ฐ๊ฟ์ค
- ๋๊ธฐ ์ค์ธ ํ๋ก์ธ์ค๊ฐ ์์ผ๋ฉด lock์ 0์ผ๋ก ์ค์
์ด ์๊ณ ๋ฆฌ์ฆ์ ๋๊ธฐ ์ค์ธ ํ๋ก์ธ์ค๋ค์ด ์์๋๋ก ์๊ณ์์ญ์ ์ ๊ทผํ ์ ์๋๋ก ๋ณด์ฅ
Atomic Variables
๐Atomic Variables: ์ธํฐ๋ฝํธ ์์ด ์์์ ์ผ๋ก(atomically) ์ ๋ฐ์ดํธํ ์ ์๋ ํน๋ณํ ๋ฐ์ดํฐ ํ์ , CAS ๊ฐ์ ํ๋์จ์ด ๋ช ๋ น์ด๋ฅผ ๊ธฐ๋ฐ์ผ๋ก ๊ตฌํ๋จ
โ ํน์ง::
integer
,boolean
๊ฐ์ basic data type์ ๋ํ ์์์ ์ฐ์ฐ ์ ๊ณต- ์ฌ๋ฌ ์ค๋ ๋/ํ๋ก์ธ์ค๊ฐ ๋์์ ์ ๊ทผํด๋ ์ผ๊ด์ฑ ์๋ ๊ฒฐ๊ณผ ๋ณด์ฅ
atomic variable ์ฃผ์ ์ฐ์ฐ
- ์ฝ๊ธฐ/์ฐ๊ธฐ ์ฐ์ฐ
load()
: ์์์ ๋ณ์์ ํ์ฌ ๊ฐ์ ์ฝ์store(val)
: ์์์ ๋ณ์์ ๊ฐ์ ์
- ์ฆ๊ฐ/๊ฐ์ ์ฐ์ฐ
increment()
: ์์์ ๋ณ์์ ๊ฐ์ 1 ์ฆ๊ฐ์ํดdecrement()
: ์์์ ๋ณ์์ ๊ฐ์ 1 ๊ฐ์์ํดfetch_add(val)
: ํ์ฌ ๊ฐ์ val์ ๋ํ๊ณ ์ด์ ๊ฐ์ ๋ฐํfetch_sub(val)
: ํ์ฌ ๊ฐ์์ val์ ๋นผ๊ณ ์ด์ ๊ฐ์ ๋ฐํ
- ๋น๊ต ๋ฐ ๊ตํ ์ฐ์ฐ
compare_exchange_strong(expected, desired)
:- ํ์ฌ ๊ฐ์ด expected์ ๊ฐ์ผ๋ฉด desired๋ก ๋ณ๊ฒฝํ๊ณ true ๋ฐํ
- ๋ค๋ฅด๋ฉด expected๋ฅผ ํ์ฌ ๊ฐ์ผ๋ก ์ ๋ฐ์ดํธํ๊ณ false ๋ฐํ
compare_exchange_weak(expected, desired)
:- strong ๋ฒ์ ๊ณผ ์ ์ฌํ์ง๋ง ํ๋์จ์ด ์ ํ์ผ๋ก ์ธํด โ๊ฑฐ์ง ์คํจโ๊ฐ ๋ฐ์ํ ์ ์์
- ์ผ๋ถ ํ๋ซํผ์์ ๋ ํจ์จ์ ์ด์ง๋ง, ์ผ๋ฐ์ ์ผ๋ก ๋ฃจํ ๋ด์์ ์ฌ์ฉ๋จ
Increment func ๊ตฌํ
1
2
3
4
void increment(atomic_int *v) {
int temp = *v;
while (!compare_and_exchange(v, &temp, temp+1));
}
- ํ์ฌ ๊ฐ
v
๋ฅผ ์์ ๋ณ์temp
์ ์ ์ฅ compare_and_exchange
๋ฅผ ์ฌ์ฉ โ ํ์ฌ ๊ฐ์ดtemp
์ ๊ฐ์์ง ํ์ธ, ๊ฐ๋ค๋ฉด ๊ฐ์temp+1
๋ก ์ ๋ฐ์ดํธ- ์ฑ๊ณตํ๋ฉด ๋ฃจํ ์ข ๋ฃ
- ์คํจํ๋ฉด(๋ค๋ฅธ ์ค๋ ๋๊ฐ ๊ฐ์ ๋ณ๊ฒฝํ๋ค๋ฉด)
compare_and_exchange
๋ temp๋ฅผ ํ์ฌ ๊ฐ์ผ๋ก ์ ๋ฐ์ดํธํ๊ณ , ๋ฃจํ๊ฐ ๋ค์ ์คํ
Atomic_Compare&Exchange(C11)
atomic_compare_exchange_strong(object, expected, desired)
:- if
object == expected
โobject โ desired
, true return - if
object != expected
โexpected โ object
, false return - ๊ฑฐ์ง ์คํจ ๋ฐ์ X
- if
atomic_compare_exchange_weak(object, expected, desired)
:- strong๊ณผ ๋์์ ๊ฐ์ง๋ง
object == expected
์์ false๋ฅผ ๋ฆฌํดํ ๊ฐ๋ฅ์ฑ์ด ์์(๊ฑฐ์ง ์คํจ) - ํ์ง๋ง ๋ฐ์ ํ๋ฅ ์ด ๋ฎ๊ณ ์๋์ ์ผ๋ก ๋น ๋ฅด๊ธฐ ๋๋ฌธ์ ๊ฑฐ์ง ํ๋จ์ด ํฌ๊ฒ ์ค์์น ์์ while๋ฌธ์ ์ฌ์ฉ
- strong๊ณผ ๋์์ ๊ฐ์ง๋ง
strong/weak ์์:
1
2
3
4
5
6
7
8
9
10
11
12
atomic_int lock = 0;
int expected = 0;
// Strong ๋ฒ์ : if๋ฌธ ์์์ ์ฌ์ฉํ ๋ ์ ํฉ
if (atomic_compare_exchange_strong(&lock, &expected, 1)) {
// ์๊ณ์์ญ ์ง์
์ฑ๊ณต
}
// Weak ๋ฒ์ : while ๋ฃจํ ์์์ ์ฌ์ฉํ ๋ ์ ํฉ
while (!atomic_compare_exchange_weak(&lock, &expected, 1)) {
expected = 0; // ์คํจ ์ expected ๊ฐ ์ฌ์ค์
}