운영체제 - 동기화
동기화(Synchronization)
여러 프로세스가 공유하는 자원의 일관성을 유지하는 것을 동기화라고 한다.
여러 프로세스가 서로 협력해 공유 자원을 사용하는 상황에서 경쟁 조건(Race Condition)이 발생하면 공유 자원의 신뢰성이 떨어진다. 이를 방지하기 위해 프로세스들이 공유자원을 사용할 때 특별한 규칙을 만든다.
프로세스 간 메시지를 전송하거나 공유 메모리를 통해 공유된 자원에 여러 개의 프로세스가 동시에 접근하면 임계 영역 문제가 발생할 수 있다.
이를 해결하기 위해 데이터를 한 번에 하나의 프로세스만 접근할 수 있도록 제한을 두는 방식이 동기화이다.
Race Condition(경쟁 조건)
여러 프로세스 혹은 스레드가 공유자원에 동시에 접근할 때 공유자원에 대한 접근 순서에 따라 실행 결과가 달라질 수 있는 상황을 의미한다. 동시에 접근하게 되면 자료의 일관성을 해친다.
- 경쟁 조건이 발생하는 상황
- 커널 모드로 수행 중 인터럽트가 발생하는 경우
- 프로세스가 시스템 콜을 호출해서 커널 모드로 수행 중인데 컨택스트 스위칭이 발생하는 경우
- 멀티 프로세스 환경에서 공유 메모리 내의 커널 데이터에 접근하는 경우
Critical Section(임계 영역)
여러 프로세스 또는 스레드가 공유 자원에 접근할 수 있는 코드 영역으로 코드 상에서 경쟁 조건이 발생할 수 있는 곳을 의미한다.
간단하게 둘 이상의 프로세스나 스레드가 동시에 접근하면 안 되는 영역을 임계 영역이라고 한다.
프로그램을 개발할 때 성능 향상을 위해서는 이러한 임계 영역을 최소화하는 설계를 해야 한다.
- 임계 영역을 해결하는 방법
- 상호 배제(Mutual Exclusion): 한 프로세스가 임계 영역에 들어갔을 경우 다른 프로세스는 들어갈 수 없다.
- 한정 대기(Bounded Waiting): 특정 프로세스가 영원히 임계 영역으로 들어가지 못하면 안 된다. 즉, 기다리는 시간이 제한적이어야 한다.
- 진행(Progress): 임계 영역에서 작업 중인 프로세스가 없다면 임계 영역에 진입하고자 하는 프로세스가 존재할 경우 해당 영역에 진입할 수 있어야 한다.
Lock
락(Lock)은 경쟁 조건을 방지하고 데이터의 일관성을 유지하기 위한 동기화 과정으로 공유 자원을 특정 스레드가 사용하고 있을 때 다른 스레드는 해당 공유 자원에 접근할 수 없도록 제한하는 것을 의미한다.
해당 락을 통해서 임계 영역에 대한 접근을 막으므로 다른 스레드의 접근을 차단할 수 있다.
Spinlock(스핀락)
락을 얻기 위해 락이 해제될 때까지 기다리며 프로세스가 무한 루프를 돌면서 회전하는 것을 스핀 락(Spinlock)이라고 한다.
스핀 락은 스레디가 이미 CPU 자원을 점유하고 있는 상태에서 락이 해제될 때까지 무한 루프를 돌기 때문에 운영 체제의 스케줄링 지원을 받지 않아 해당 스레드에 대한 컨택스트 스위칭이 일어나지 않는다.
- 스핀락의 장점
- 컨택스트 스위칭이 발생하지 않아 CPU의 오버헤드를 줄일 수 있어 경쟁 조건이 짧을 경우 유용하다.
- 락의 획득과 해제가 빠르다
- 스핀락의 단점
- 무한 루프 자체가 CPU 자원을 많이 잡아먹는다.
- 임계 영역이 여러 개 혹은 락이 반환될 때까지 오랜 시간이 걸린다면 Busy waiting과 Stravation을 갖는다.
- 스핀 락은 컨택스트 스위칭이 일어나지 않기 때문에 멀티 프로세서 환경에서만 사용할 수 있다.
Mutex(뮤텍스)
공유된 자원의 데이터 혹은 임계 영역 등에 하나의 프로세스 혹은 스레드가 접근하는 것을 막아준다.
임계 영역을 가진 스레드들의 실행 시간이 서로 겹치지 않고 단독으로 실행되도록 상호 배제하는 기술이다.
얼핏 보면 앞서 살펴본 스핀 락과 유사해 보이지만 스핀 락과는 다르게 권한을 획득할 때까지 Busy waiting 상태에 머무르지 않고 sleep 상태로 들어갔다가 wakeup 되면 다시 권한 획득을 시도하는 sleep lock을 사용한다.
임계 구역을 보호하고 경쟁 조건을 방지하기 위해 mutex lock을 사용하게 되는데 락을 걸은 스레드만 임계 영역으로 들어갈 수 있고 나갈 때 락을 해제한다.
락을 소유한 프로세스 혹은 스레드만이 공유 자원에 접근할 수 있기 때문에 두 스레드가 동시에 사용할 수 없고 동기화 대상이 하나로 제한된다.
Semaphore(세마 포어)
세마포어는 Busy waiting이 필요 없는 동기화 방법이며 여러 프로세스 또는 스레드가 임계 영역에 접근할 수 있는 Signaling 메커니즘이다.
세마포어는 카운터(Counter)를 이용하여 동시에 자원에 접근할 수 있는 프로세스를 제한하게 된다.
카운터는 주로 S라는 정수형 변수로 나타내며 이는 사용 가능한 자원의 개수를 의미한다. 이러한 S 값이 0이 되면 다른 프로세스나 스레드를 대기하도록 하여 상호 배제를 달성할 수 있다.
세마포어는 프로세스가 임계 구역에 들어가려고 할 때 wait()를 호출해 S값을 감소시키고 임계구역 작업을 끝낸 뒤, lock을 반납할 때 signal()을 호출해 S값을 증가시킨다.
세마포어는 뮤텍스와 다르게 Signaling 메커니즘으로 락을 걸지 않은 스레드도 signal을 사용해 락을 해제할 수 있다.
또한 뮤텍스는 오직 1개의 프로세스 혹은 스레드만 공유 자원에 접근할 수 있지만, 세마포어는 S 값만큼의 프로세스 혹은 스레드가 접근할 수 있다.
앞서 설명했던 리소스의 상태를 나타내는 정수 값인 S를 카운팅 하기 위해 간단한 카운터로 Counting Semaphore와 Binary Semaphore로 나뉠 수 있다.
- Counting Semaphore
정수 값의 범위가 0 이상으로 제한이 없어 S값이 무한대로 증가할 수 있다.
주로 자원의 개수를 세는 데 사용되는데 프로세스가 자원을 사용할 경우 wait() 함수를 실행하여 사용 가능한 자원의 개수인 S를 줄여주고, 프로세스가 자원을 반납할 경우 signal() 함수를 실행하여 S의 개수를 늘려준다.
- Binary Semaphore
Binary Semaphore는 이진수를 사용하여 세마포어를 사용하는 프로세스는 그 값을 확인하고 자원을 사용하는 동안에는 그 값을 변경함으로써 다른 세마포어 사용자들이 기다리도록 하는 방법이다.
정수 값이 오직 0 또는 1이므로 똑같이 0, 1의 상태를 갖는 뮤텍스와 동일한 역할을 갖는다.
모니터(Monitor)
세마포어 방법은 코딩하기 힘들고 실수하기 쉬우며 정확성을 입증하기가 어렵다. 이러한 단점을 보완할 수 있는 구조가 모니터(Monitor)이다.
모니터는 동시 수행 중인 프로세스 사이에서 추상 데이터의 안전한 공유를 보장하기 위한 High-level 동기화 구조이다. 공유 데이터를 접근하기 위해서는 모니터 내부의 Procedure를 통해서만 접근할 수 있다.
세마포어와의 가장 큰 차이점은 락을 걸 필요가 없다는 것이다. 모니터는 자체적인 기능으로 해결할 수 있다.
모니터는 공유 데이터 구조, 공유 데이터에 대한 연산을 제공하는 프로시저, 현재 호출된 프로시저간의 동기화를 캡슐화한 모듈이다.
동일한 시간엔 오직 한 프로세스나 스레드만 모니터에 들어갈 수 있다. 따라서 모니터에 진입하려고 했는데 내부에 프로세스가 들어가 있어 진입하지 못한 프로세스들은 모니터 큐에서 기다리게 된다.
프로세스가 모니터 내에서 기다릴 수 있게 하도록 조건 변수가 사용된다.
조건 변수는 오직 wait와 signal 연산만으로 사용될 수 있는데 세마포어 변수와 유사하지만 변수가 어떤 값을 가지진 않고, 자신의 큐에 프로세스를 매달아서 sleep 시키거나 큐에서 프로세스를 깨우는 역할만 한다.
참고 자료
[운영체제(OS)] 6. 프로세스 동기화(Process Synchronization)
[목차] 1. Race Condition 2. Critical Section 3. Synchronization Algorithms 4. Synchronization Hardware 5. Mutex Locks 6. Semaphores 7. Classical Problems of Synchronization 8. Monitor 참고) - https://parksb.github.io/article/10.html - KOCW 공개강의
rebro.kr
[OS] 뮤텍스와 세마포어 (Mutex and Semaphore)
뮤텍스와 세마포어 (Mutex and Semaphore)
hoyeonkim795.github.io