[OS] Operating System(6-2): Mutax lock, Semaphore
๐ ์ด์์ฒด์ ์ ๊ณต ์์ ์ ๋ฆฌ
์ด์ ์ ๋ณธ ํ๋์จ์ด ๊ธฐ๋ฐ ํด๊ฒฐ์ฑ ๋ค(Test-and-Set,CAS,atomic ๋ณ์ ๋ฑ)์ ๊ฐ๋ ฅํ์ง๋ง ์ง์ ์ฌ์ฉํ๊ธฐ์๋ ๋ณต์กํ๊ณ ์ ๊ทผํ๊ธฐ๊ฐ ์ด๋ ต๋ค!
๊ทธ๋์ ์ด๋ฌํ ํ๋์จ์ด ๊ธฐ๋ฅ์ ๊ธฐ๋ฐ์ผ๋ก ๋ ๋์ ์์ค์ software๋๊ตฌ๋ฅผ ์ ๊ณตํ๋ค.
๊ทธ ์ค ๊ธฐ๋ณธ์ ์ธ ๊ฒ์ด Mutex Lock
Mutex Locks
๐Mutex Lock: cs ๋ฌธ์ ๋ฅผ ํด๊ฒฐํ๊ธฐ ์ํ software tool, Mutual Exclusion์ ์ค์๋ง, ์ฌ๋ฌ ์ค๋ ๋๋ ํ๋ก์ธ์ค๊ฐ ๊ณต์ ์์์ ๋์์ ์ ๊ทผํ๋ ๊ฒ์ ๋ฐฉ์ง
- critical section์ ๋ณดํธํ๊ธฐ ์ํด ๋จผ์
acquire()
๋ก lock์ ํ๋, ๋์ค์release()
๋ก lock์ ํด์ - boolean variable์ ์ฌ์ฉํ์ฌ lock์ ๊ฐ์ฉ์ฑ์ ๋ํ๋
acquire()
,release()
๋ ์์์ ์ผ๋ก ๊ตฌํ๋์ด์ผํจ
Mutex Lock์ ๊ตฌ์กฐ
1
2
3
4
5
6
while (true) {
acquire lock
critical section
release lock
remainder section
}
Mutex Lock์ ๊ตฌํ
1
2
3
4
5
6
7
8
9
acquire() {
while (!available)
; /* busy wait */
available = false;
}
release() {
available = true;
}
์ด ํจ์๋ค์ ์์์ ์ผ๋ก ์คํ ๋์ด์ผํจ
โ Test-and-Set, Compare-and-Swap๊ณผ ๊ฐ์ ํ๋์จ์ด ๋ช
๋ น์ด๋ฅผ ์ฌ์ฉํจ
- Test-and-Set ```c acquire() { while (test_and_set(&lock)) ; /* busy wait */ }
release() { lock = false; }
1
2
3
4
5
6
7
8
9
10
11
* **Compare-and-Swap**
```c
acquire() {
while (compare_and_swap(&lock, 0, 1) != 0)
; /* busy wait */
}
release() {
lock = 0;
}
์์ Mutex lock ๊ตฌํ์์๋ ํ๋ก์ธ์ค๊ฐ lock์ ํ๋ํ ์ ์์ ๋ ๊ณ์ํด์ CPU๋ฅผ ์๋นํ๋ฉฐ ๋๊ธฐํ๋ค. ์ด๋ฅผ Busy waiting or Spinlock ์ด๋ผ ํ๋ค.
โ Spinlock ํน์ง:
- ํ๋ก์ธ์ค๊ฐ lock์ ๊ธฐ๋ค๋ฆฌ๋ ๋์ ๊ณ์ CPU๋ฅผ ์๋น
- Context Switching ๋ฐ์ X
- lock ๋ณด์ ์๊ฐ์ด ์งง๊ณ ๊ฒฝ์์ด ์ ์ ํ๊ฒฝ์์ ํจ์จ์
- ๋ค์ค ์ฝ์ด/ํ๋ก์ธ์ ํ๊ฒฝ์์ ์ ํฉ
๐Spinlock ์ ๋ฆฌํ ์ํฉ:
โlock์ ๋ณด์ ํ๋ ์๊ฐ < ๋ ๊ฐ์ context switching ์๊ฐโ ์ ๊ฒฝ์ฐ์ Spinlock ์ ๋ฆฌํจ โ lock์ ์ป๊ธฐ ์ํด block ๋๊ณ ๋ค์ ๊บ ์ด๋๋ ์ค๋ฒํค๋๋ณด๋ค ์งง์ ์๊ฐ ๋์ CPU ์๋นํ๋ฉฐ ๋๊ธฐํ๋ ๊ฒ์ด ๋ ํจ์จ์ ์ด๊ธฐ ๋๋ฌธ!
Semaphore
๐Semaphore: Mutex lock๋ณด๋ค ๋ ์ ๊ตํ ํ๋ก์ธ์ค๊ฐ ๋๊ธฐํ๋ฅผ ์ ๊ณต
- Semaphore S: integer variable - ์ฌ์ฉ ๊ฐ๋ฅํ ์์ ์
- ๋ ๊ฐ์ง ์์์ ์ฐ์ฐ:
wait(S)
=P(): semaphore ๊ฐ์ ๊ฐ์์ํค๊ณ , ๊ฐ์ด ์์๋ฉด ํ๋ก์ธ์ค๋ฅผ ๋ธ๋กsignal(S)
=V(): semaphore ๊ฐ์ ์ฆ๊ฐ์ํค๊ณ , ๋๊ธฐ ์ค์ธ ํ๋ก์ธ์ค๊ฐ ์์ผ๋ฉด ๊นจ์ด๋ค
wait(S) operation
1
2
3
4
5
wait(S) {
while (S <= 0)
; // busy wait
S--;
}
signal(S) operation
1
2
3
signal(S) {
S++;
}
Semaphore Usage
semaphore๋ ๊ฐ์ ๋ฒ์์ ๋ฐ๋ผ ๋ ๊ฐ์ง ์ ํ์ผ๋ก ๋๋๋ค.
- Binary Semaphore
- ์ธ๋งํฌ์ด ๊ฐ์ด
0๊ณผ 1
์ฌ์ด๋ก๋ง ์ ํ๋จ - Mutex lock๊ณผ ๋์ผํ ๊ธฐ๋ฅ์ ์ ๊ณต
- Mutual exclusion๋ฅผ ๊ตฌํํ๋ ๋ฐ ์ฌ์ฉ๋จ
- ์ด๊ธฐ๊ฐ์ ๋ณดํต 1๋ก ์ค์ ๋์ด, ์ฒซ ๋ฒ์งธ ํ๋ก์ธ์ค๊ฐ ์์์ ์ ๊ทผํ ์ ์๊ฒ ํจ
- ์ธ๋งํฌ์ด ๊ฐ์ด
- Counting Semaphore
- ์ธ๋งํฌ์ด ๊ฐ์ด ์ ํ ์๋ ์์ญ์์ ๋ณํ ์ ์๋ค
- ๋์์ ์ฌ์ฉ ๊ฐ๋ฅํ ์์์ ๊ฐ์๋ฅผ ์ ์ดํจ
- ์๋ฅผ ๋ค์ด, 10๋์ ํ๋ฆฐํฐ๋ฅผ ๊ด๋ฆฌํ๋ ์ธ๋งํฌ์ด๋ ์ด๊ธฐ๊ฐ์ด 10์ด ๋ ์ ์๋ค
Semaphore ํ์ฉ ์์
์ธ๋งํฌ์ด๋ฅผ ํ์ฉํด ํ๋ก์ธ์ค ๊ฐ ๋๊ธฐํ ๋ฌธ์ ๋ฅผ ํด๊ฒฐํ๋ ์์
- ๋ฌธ์ : P1์ S1 ์คํ ํ์๋ง P2์ S2๊ฐ ์คํ๋๋๋ก ๋ณด์ฅ
1
2
3
4
5
6
7
8
9
10
11
12
// ์ธ๋งํฌ์ด ์ด๊ธฐํ
semaphore sync = 0; // ์ด๊ธฐ๊ฐ 0์ผ๋ก ์ค์
// ํ๋ก์ธ์ค Pโ
P1:
Sโ;
signal(sync); // sync ๊ฐ์ 1๋ก ์ฆ๊ฐ
// ํ๋ก์ธ์ค Pโ
P2:
wait(sync); // sync๊ฐ ์์๊ฐ ๋ ๋๊น์ง ๋๊ธฐ
Sโ;
semaphore sync
๋ ์ด๊ธฐ๊ฐ์ด 0- P2๋
wait(sync)
๋ฅผ ํธ์ถํ๋ฉด ์ฆ์ ๋ธ๋ก๋จ(sync=0
์ด๋ฏ๋ก) - P1์ด S1์ ์ํํ๊ณ
signal(sync)
๋ฅผ ํธ์ถํ๋ฉดsync=1
์ด ๋๋ค - ์ด์ P2๋ ๋ธ๋ก ์ํ์์ ๋น ์ ธ๋์ S2๋ฅผ ์ํํ ์ ์๊ฒ ๋๋ค
Semaphore Implementation with no Busy waiting
์์ ์ธ๋งํฌ์ด ๊ตฌํ์๋ buzy waiting ๋ฌธ์ ๊ฐ ์๋ค.
์ด๋ฅผ ํด๊ฒฐํ๊ธฐ ์ํด waiting queue๋ฅผ ์ฌ์ฉํด ์ธ๋งํฌ์ด๋ฅผ ๊ตฌํ!
- semaphore ๊ตฌ์กฐ์ฒด:
1
2
3
4
typedef struct {
int value; // ์ธ๋งํฌ์ด ๊ฐ
struct process *list; // ๋๊ธฐ ์ค์ธ ํ๋ก์ธ์ค ๋ฆฌ์คํธ
} semaphore;
โ ๊ตฌ์กฐ์ฒด์ ๋ ๊ฐ์ง ์์:
value
: ์ธ๋งํฌ์ด์ ์ ์ ๊ฐ์ผ๋ก, ์ฌ์ฉ ๊ฐ๋ฅํ ์์์ ์๋ฅผ ๋ํ๋ธ๋คlist
: ์ธ๋งํฌ์ด๋ฅผ ๊ธฐ๋ค๋ฆฌ๋ ํ๋ก์ธ์ค๋ค์ ์ฐ๊ฒฐ ๋ฆฌ์คํธ(linked list)
์ธ๋งํฌ์ด ๊ตฌํ์๋ ๋ ๊ฐ์ง ์ฐ์ฐ์ด ์ฌ์ฉ๋๋ค
- block operation:
- ์ธ๋งํฌ์ด๋ฅผ ๊ธฐ๋ค๋ฆฌ๋ ํ๋ก์ธ์ค๋ฅผ ์ ์ ํ
waiting queue
์ ๋ฃ์ - ํ๋ก์ธ์ค๋ฅผ
์คํ ์ํ โ ๋๊ธฐ ์ํ
๋ก ์ ํ
- ์ธ๋งํฌ์ด๋ฅผ ๊ธฐ๋ค๋ฆฌ๋ ํ๋ก์ธ์ค๋ฅผ ์ ์ ํ
- wakeup operation
waiting queue
์์ ํ๋ก์ธ์ค๋ฅผ ํ๋ ์ ๊ฑฐ- ์ ๊ฑฐ๋ ํ๋ก์ธ์ค๋ฅผ
๋๊ธฐ ์ํ โ ready ์ํ
๋ก ์ ํ
Implementation on single-core system
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
wait(semaphore *S) {
disable interrupts; // ์ธํฐ๋ฝํธ ๋นํ์ฑํ
S->value--; // ์ธ๋งํฌ์ด ๊ฐ ๊ฐ์
if (S->value < 0) { // ์์์ ์ฌ์ฉํ ์ ์๋ ๊ฒฝ์ฐ
add this process to S->list; // ๋๊ธฐ ํ์ ์ถ๊ฐ
block(); // ํ๋ก์ธ์ค ๋ธ๋ก
}
enable interrupts; // ์ธํฐ๋ฝํธ ํ์ฑํ
}
signal(semaphore *S) {
disable interrupts; // ์ธํฐ๋ฝํธ ๋นํ์ฑํ
S->value++; // ์ธ๋งํฌ์ด ๊ฐ ์ฆ๊ฐ
if (S->value <= 0) { // ๋๊ธฐ ์ค์ธ ํ๋ก์ธ์ค๊ฐ ์๋ ๊ฒฝ์ฐ
remove a process P from S->list; // ๋๊ธฐ ํ์์ ํ๋ก์ธ์ค ์ ๊ฑฐ
wakeup(P); // ํ๋ก์ธ์ค ๊นจ์ฐ๊ธฐ
}
enable interrupts; // ์ธํฐ๋ฝํธ ํ์ฑํ
}
- single core์์๋ interrupt disable๋ง์ผ๋ก ์์์ฑ์ ๋ณด์ฅ โ ๊ตฌํ์ด ๊ฐ๋จ
- S->value:
S->value
> 0: ์ฌ์ฉ ๊ฐ๋ฅํ ์์์ ์S->value
<= 0: ๋๊ธฐ ์ค์ธ ํ๋ก์ธ์ค์ ์๋ **S->value ๊ฐ**
Implementation on multicore system
multicore ์์คํ
์์๋ ๊ฐ ์ฝ์ด๊ฐ ๋
๋ฆฝ์ ์ผ๋ก ์คํ๋๊ณ , ํ ์ฝ์ด์์ ์ธํฐ๋ฝํธ๋ฅผ ๋นํ์ฑํํด๋ ๋ค๋ฅธ ์ฝ์ด๋ ์คํ ๋๋ค
โ ์ธํฐ๋ฝํธ ๋นํ์ฑํ๋ง์ผ๋ก๋ ์์์ฑ์ ๋ณด์ฅ X
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
wait(semaphore *S) {
while (test_and_set(&S->&mutex)) // mutex ํ๋ ์๋, ์ธ๋งํฌ์ด๋ง๋ค mutex๊ฐ ๋ฐ๋ก ์์ด์ผํจ
; /* spinlock */ // ํ๋ํ ๋๊น์ง ์คํ
S->value--; // ์ธ๋งํฌ์ด ๊ฐ ๊ฐ์
if (S->value < 0) { // ์์์ ์ฌ์ฉํ ์ ์๋ ๊ฒฝ์ฐ
add this process to S->list; // ๋๊ธฐ ํ์ ์ถ๊ฐ
S->mutex = 0; // mutex ํด์
block(); // ํ๋ก์ธ์ค ๋ธ๋ก
}
else
S->mutex = 0; // mutex ํด์
return;
}
signal(semaphore *S) {
while (test_and_set(&S->&mutex)) // mutex ํ๋ ์๋
; /* spinlock */ // ํ๋ํ ๋๊น์ง ์คํ
S->value++; // ์ธ๋งํฌ์ด ๊ฐ ์ฆ๊ฐ
if (S->value <= 0) { // ๋๊ธฐ ์ค์ธ ํ๋ก์ธ์ค๊ฐ ์๋ ๊ฒฝ์ฐ
remove a process P from S->list; // ๋๊ธฐ ํ์์ ํ๋ก์ธ์ค ์ ๊ฑฐ
S->mutex = 0; // mutex ํด์
wakeup(P); // ํ๋ก์ธ์ค ๊นจ์ฐ๊ธฐ
}
else
S->mutex = 0; // mutex ํด์
return;
}
- Spinlock ์ฌ์ฉ: Test-and-Set๊ณผ ๊ฐ์ ํ๋์จ์ด ์ง์ ๋ช ๋ น์ด๋ฅผ ์ฌ์ฉํ Spinlock์ผ๋ก ์๊ณ์์ญ์ ๋ณดํธ
- ๋ค์ค ์ฝ์ด์์๋ ์คํ๋ฝ์ ํตํด ํ ๋ฒ์ ํ ํ๋ก์ธ์ค๋ง ์ธ๋งํฌ์ด๋ฅผ ์์ ํ ์ ์๋๋ก ํด์ ์์์ฑ์ ๋ณด์ฅ
- mutex ๋ณ์: ์ธ๋งํฌ์ด ์ฐ์ฐ์ ์์์ฑ์ ๋ณด์ฅํ๊ธฐ ์ํ ์ด์ง ๋ณ์
- ๋ธ๋ก ์ mutex ํค์ : ํ๋ก์ธ์ค๊ฐ ๋ธ๋ก๋๊ธฐ ์ ์ ๋ฐ๋์ mutex๋ฅผ ํด์ ํด์ผ ๋ฐ๋๋ฝ ๋ฐฉ์ง ๊ฐ๋ฅ