Shine's dev log

프로세스 동기화_2 (HW동기화, Mutex, Semaphore) 본문

운영체제

프로세스 동기화_2 (HW동기화, Mutex, Semaphore)

dong1 2020. 5. 31. 23:15

앞서 살펴본 소프트웨어적 Synchronization인 peterson's 알고리즘 같은경우도 실제 컴퓨터에서는 완벽한 동기화 방법이 아니다.

 

peterson 알고리즘은 atomic하다는 전제로는 잘 돌아가지만, non-atomic할 경우 제대로 돌아가지 않는다.

 

여기서 non-atomic이란, 같은 메모리에 두개의 값이 경쟁해서 들어가려고할 때 두개의 값 말고 뜬금없는 값이 들어가는 것을 말한다. 예를 들어, a라는 변수에 쓰레드1에서는 1을 넣으려고하고, 쓰레드2에서는 2를 넣으려고 할 때 atomic한 경우 a에 1이나 2가 저장되만, non-atomic한 경우 뜬금없는 4가 저장될 것이다.

 

그래서 하드웨어적으로 동기화 시키는 방법을 사용해야 한다.

 

 

 

1. Diabling Interrupts

 

인터럽트를 꺼서 lock을 구현하는 방법이다.

 

보통 메모리에 값을 저장할 때, [read - compute - update]의 과정을 거치게 되는데, 이 과정동안 인터럽트를 꺼서 중간에 다른 쓰레드한테 방해를받지 않도록 하는 작전이다.

 

즉, [read - compute - update]를 쪼갤 수 없는 한 덩어리로 만드는 것이다.

 

이렇게 하면, [read - compute - update] 이 과정중에 context switch를 막을 수 있고, 자연스럽게 동기화 문제도 해결이 된다.

 

하지만, 이 방식의 경우 문제점이 있다.

 

문제점1) 인터럽트를 맘대로 끄면 문제 발생가능

문제점2) 멀티코어 시스템에서는 불가능 (모든 코어의 인터럽트가 꺼지므로 더 오래걸린다.)

 

 

 

2. Test - And - Set

 

Tes-And-Set은 Atomic instruction을 이용하는 방식이다. (instruction은 다 수행이 되던지, 아예 다 수행이 안되던지 하는 것)

 

특정 변수를 Test해서 그 값이 원하는 값이면, 새로운 값으로 바꿔주는 식으로 작동한다.

 

Test-And-Set을 이용하면 Mutual exclusion을 만족시킬 수 있다.

 

x86에서는 xchg 명령어를 사용한다.

 

 

 

3. Compare - And - Swap

 

역시 Atomic instruction 을 이용한다.

 

Test-And-Set과 비슷하지만, expected 변수가 하나 더 추가되는 방식이다.

 

x86에서는 cmpxchg 명령어를 사용한다.

 

 

하지만 이런 HW적인 것은 일반적으로 프로그램 짜는 입장에서는 고려하기 빡세다. 그래서 Higher-level에서는 이것보다 간단하게 데이터 동기화를 해주는데 1) Mutex locks 2) Semaphores 3) monitor 4) condition variables 등의 방식을 사용한다.

 

 

 

4. Mutex Lock

 

Mutual exclusive Lock이란 뜻이다.

 

acquire() 함수를 이용해 lock을 잡고, release() 함수를 이용해 lock을 푼다.

 

한마디로 화장실 문고리같은 거라고 생각하면 된다.

 

Mutex lock에는 두가지 방법이 있다.

 

1) busy wait 하는 Mutex

 

- 계속해서 화장실 문고리 흔드는 것.

- acquire() 계속 시도. (spinlock)

 

2) block하는 Mutex

 

- 나올 떄까지 기다리는 것.

 

보통 Mutex Lock은 HW 가 서포트해주는 atomic instructions를 사용한다.

 

 

여기서 잠깐 spinlock을 살펴보고 가자.

spinlock & mutexl lock

 

위의 그림처럼 spinlock은 Mutex lock에 포함되는 개념이다.

 

Spin lock의 장점

 

1) 구현하기 간단하다.

2) context switch 필요 없다. (block하는경우, 잠겨있으면 다음 프로세스로 넘어간다.)

3) 그래서 acquire - release 사이가 짧은 경우 유리하다.

 

Spin lock의 단점

 

1) 시스템 resource를 많이 잡아먹는다.

2) lock holder 쓰레드가 preempted 될 경우, starvation이 발생할 수 있다.

 

 

 

5. Semaphore

 

Semaphore는 locks보다 높은 레벨의 동기화를 구현해준다.

 

S라는 하나의 int형 변수를 두고, S가 state를 나타내도록 하는 방식으로, 최대 S개의 task가 semaphore를 동시에 잡을 수 있다.

 

즉, lock과 비슷한데 한개 이상의 entity가 동시에 잡을 수 있다는 차이가 있다.

 

Semaphore를 구현할 때 사용하는 operation을 살펴보자.

 

1) wait() - S를 1 내리고, S가 0보다 같거나 커질때까지 기다린다.

 

2) signal() - S를 1 올리고 나간다.

 

 

Semaphore의 종류는 두가지가 있다.

 

1) Binary Semaphore ( = Mutex )

 

- S는 1로 초기화 되어있다.

- Mutually exclusive access를 보장해준다.

 

2) Counting semaphore

 

- N(1이 아님) 로 초기화 되어있다.

- 많은 unit 들이 resource 접근 가능하다.

 

 

오늘 배운 내용을 정리해보면,

 

1. 하드웨어적으로 동기화를 구현하는 방법으로는 1) 인터럽트를 끄거나 2) Test and Set 3) compare and Set 방법들이 있다.

 

2. 실제 프로그래머들은 주로 Mutex나 Semaphore를 이용해 동기화를 시킨다.

 

 

본 내용은 공부하며 정리한 것으로, 오류가 있을 수 있습니다.