개요
Mutex와 Semaphore를 알기 전에 경쟁 상태와 임계 영역에 대해서 먼저 알아야 한다.
경쟁 상태(Race Condition)
여러 프로세스 또는 스레드에서 하나의 공유 자원에 접근하는 경우가 있는데 이 때 자원에 접근하는 순서에 따라 결과 값이 달라질 수 있다.
이러한 현상을 공유 자원에 접근해 경쟁하는 상태라고 해서 경쟁 상태라 한다.
경쟁 상태를 가장 알기 쉽게 표현한 예를 알아보자
우유가 없어 한 개의 우유가 필요한 상황이다.
1.
엄마가 냉장고에 우유가 없는 것을 확인한다.
2.
엄마가 우유를 사러 슈퍼마켓에 간다.
3.
엄마가 우유를 사고 돌아오는 길에 아빠가 냉장고에 우유가 없는 것을 확인한다.
4.
아빠가 우유를 사러 슈퍼마켓에 간다
5.
아빠가 우유를 사온다.
우유가 한개가 필요한 상황인데 프로세스(엄마, 아빠)간에 동기화가 되지 않아 엄마가 우유를 사러 간 것을 모르는 아빠가 우유를 사와
우유가 2개가 되었다.
이러한 문제를 해결하기 위해 프로세스 간에 동기화가 필요하다.
임계 영역(Critical Section)
공유 자원에 접근할 수 있고 접근 순서에 따라 결과가 달라지는 코드 영역을 임계 영역이라한다.
이 임계영역에서 경쟁 상태가 발생하는 것을 방지하려면 여러 프로세스가 공유 자원에 접근해도 데이터의 일관성이 유지되도록 프로세스 동기화를 해야 한다.
임계영역에서 여러 접근이 동시에 접근하는 것을 방지하려면 아래 조건들을 만족해야 한다.
1.
상호배제 기법
어떤 프로세스가 임계 영역을 실행 중일 때 다른 프로세스가 임계 영역에 접근할 수 없다. 상호배제 기법으로는 뮤텍스와 세마포어가 있다.
2.
진행(Progress)
임계 영역을 실행 중인 프로세스가 없을 때 다른 프로세스가 임계 영역을 실행한다.
3.
한정된 대기
임계 영역에 접근을 요청했을 때 무한한 시간을 기다리지 않는다.
뮤텍스 (Mutex)
뮤텍스는 락을 가진 스레드만이 공유 자원에 접근할 수 있게 하는 방법이다.
뮤텍스는 스레드 간 상호 배제를 위한 잠금 메커니즘이다.
예를 들어 설명하자면, 화장실과 화장실 열쇠가 하나뿐인 식당을 들 수 있다. 키를 가진 손님 한 명만이 화장실에 들어갈 수 있다.
화장실은 임계영역, 화장실 키는 락으로 생각하면 이해가 쉽다. 임계 영역에 접근한 프로세스가 임계 영역에 락을 건다고 해서 락킹 매커니즘이라고 한다.
임계 영역에 접근하지 못한 스레드는 락을 얻기 위해 기다리는 동안 락이 풀렸는지 반복문을 돌면서 확인한다.
이를 바쁜 대기(busy waiting)의 한 종류인 스핀락(SpinLock)이라 한다.
사용사례
로그 파일에 동시 쓰기를 방지하거나 캐시 갱신 시 충돌 방지를 위한 뮤텍스 사용 사례를 들 수 있다.
뮤텍스의 장단점
•
장점
◦
단일 자원에 대해 상호 배제를 제공하기 때문에 매우 직관적이고 쉽게 사용할 수 있다.
◦
공유 자원의 무결성을 보장할 수 있다.
▪
한 스레드만 접근이 가능하기 때문에 무결성은 보장된다.
◦
가벼운 락
▪
카운터를 관리할 필요가 없기 때문에 오버헤드가 비교적 적어 성능 저하를 최소화 할 수 있다.
•
단점
◦
뮤텍스는 기본적으로 스레드 간 상호 배제를 위한 도구이기 때문에 프로세스 간 동기화에는 사용할 수 없다.
◦
자원을 잠그고 해제하는 과정에서 컨텍스트 스위칭이 발생할 수 있다.
◦
락 경합이 심한 경우 락을 기다리는 시간이 길어져 성능 저하가 발생할 수 있다.
◦
뮤텍스 역시 데드락 위험이 존재한다.
▪
여러 스레드가 교차하여 자원을 잠그는 상황에서 스레드들이 서로 자원의 잠금이 풀리기를 기다리면서 데드락에 빠질 수 있다.
◦
우선순위가 낮은 스레드가 락을 소유하고 있을 때, 우선순위가 높은 스레드가 해당 락을 기다리게 되어 성능 저하가 발생할 수 있다. (우선순위 역전)
세마포어 (Semaphore)
세마포어는 뮤텍스와 다르게 공유 자원에 접근할 수 있는 프로세스 수를 정해 접근을 제어하는 방법이다.
세마포어는 특정 자원에 대한 접근을 제한하는 카운터 기반의 동기화 메커니즘이다.
사용사례
세마포어는 DB 커넥션 풀 관리에서 적절한 커넥션 풀 숫자를 설정하여 사용할 수 있다.
세마포어의 장단점
•
장점
◦
임계 영역에 하나 이상의 스레드가 접근하는 것이 가능하다.
◦
프로세스 간 동기화에도 사용할 수 있다.
◦
동기화 기능을 제공하기 때문에 여러 스레드가 특정 조건을 만족할 때까지 대기하도록 설정할 수 있다.
•
단점
◦
세마포어는 카운터를 관리해야 하므로 상태 관리가 복잡할 수 있다.
▪
wait()을 너무 많이 호출하면 카운터가 음수가 되는 버그가 발생할 수 있다. (세마포어 카운터는 무조건 양수이다)
◦
여러 스레드가 세마포어를 사용할 때 데드락이 발생할 수 있다.
▪
스레드가 자원을 확보한 뒤 signal()을 호출하지 않거나 wait()호출을 잘못하는 경우 교착상태에 빠질 수 있다.
◦
기아 상태 발생 가능성
▪
자원의 개수가 적고 스레드의 개수가 많은 경우 특정 스레드가 영원히 자원을 획득하지 못하는 기아 상태에 빠질 수 있다.