Operating System : 뮤텍스(Mutex) / 세마포어(Semaphore) / 모니터(Monitor)
뮤텍스(Mutex) / 세마포어(Semaphore) / 모니터(Monitor)
뮤텍스(Mutex)
,세마포어(Semaphore)
, 모니터(Monitor)
전부 운영체제의 상호배제(Mutual Exclusion) 동기화 기법
입니다.
뮤텍스(Mutex)
뮤텍스(Mutex)
는 상호배제(MUTual EXclusion)의 머릿글자를 따서 만들어졌습니다. 0또는 1의 값을 가지는 이진 세마포어와 유사합니다. Critical Section (임계구역)
을 가진 스레드들의 실행 시간을 서로 겹치지 않게 단독으로 실행하게 하는 기술입니다. 다른 프로세스(애플리케이션)간에 동기화할 때 사용할 수 있습니다.
-
프로세스들의 공유 리소스에 대한 접근을 조율하기 위해
Locking
과Unlocking
을 사용합니다. -
뮤텍스 객체를 두 스레드가 동시에 사용할 수 없습니다.
예시
일부 음식점들은 공용 화장실(공유 자원)
관리 차원에서 화장실을 잠궈두고(Locking
) 다닙니다. 손님들이 화장실에 가려면 주인에게 열쇠(Lock)
를 받은 후 가야합니다. 물론 다음 손님이 공용 화장실(공유 자원)
에 가려면 앞 손님이 열쇠(Lock)
를 반납해야 갈 수 있습니다.
이렇게 열쇠(Lock)
를 가지고 있는 경우에만 공유자원(화장실)
에 접근할 수 있습니다. 이게 바로 뮤텍스(Mutex)
라고 보면 됩니다. 유의할 점은 Lock
에 대한 소유권이 있다는 점입니다. 열쇠를 획득한 사람만 반납할 수 있습니다.
세마포어(Semaphore)
프로세스간의 시그널(신호, Signal)
을 주고받기 위해 사용되는 정수 값, 리소스의 상태(허용 가능한 Counter의 갯수)를 나타내는 카운터로 세마포어는 다음 세가지 원자적인 연산만을 지원합니다.
-
initialize : 세마포어 초기화. (음이 아닌 정수값으로 초기화)
-
decrement : 프로세스를 블록시킬 수 있습니다.
-
increment : 블록되었던 프로세스를 깨울 수 있습니다. 이 세마포어를 카운팅 세마포어 또는 범용 세마포어라고 합니다.
세마포어의 값에 따라 운영체제는 프로세스가 즉시 자원을 사용할 지 정합니다. 자원이 다른 프로세스에 의해 사용 중인걸 알게 될 경우엔 일정 시간을 기다려야 합니다. 프로세스가 자원을 사용하는 동안에는 세마포어 값을 변경함으로서 다른 프로세스들이 기다리게 해야합니다.
예시
107호 병실(임계 구역)
에 방문객용 의자가 5개(임계구역 안의 자원)
있다고 했을 때, 간호사(세마포어)
는 이 병실에 방문자가 5명(Counter 개수)만 들어갈 수 있도록 허용하고 나머지 방문객들은 밖에서 대기하도록 합니다. Counter 개수
만큼 임계 구역(병실)
에 접근할 수 있습니다.
이 세마포어 Counter의 개수에 따라
1개의 경우 이진 세마포어(Binary Semaphore)
, 2개 이상의 경우 카운팅 세마포어(Counting Semaphore)
라고 불립니다. Binary Semaphore
의 경우 개념적으로 Mutex
와 같다고 볼 수 있습니다.
의문점
상호배제(Mutual Exclusion)
를 생각해보면, 카운팅 세마포어(Counting Semaphore)
가 이상해 보입니다. 분명 하나의 자원에는 하나의 프로세스만 접근할 수 있기 때문입니다. 그렇다면 카운팅 세마포어는 상호 배제를 깨는 것일까요??
맞습니다. 다만, 상호 배제를 깨는건 맞는데 제한적으로 그러니까 임계값 만큼이 동시에 깰 수 있게 됩니다.
위의 병실을 예를 들어 설명해보자면, 임계구역(병실)
에 1이라는 자원(의자 1개)
만 있는데 이 1(의자)
을 사용하는 스레드(방문자)
가 여러개가 된다는 것이 아니라,1,2,3,4,5라는 자원(의자 5개)
을 5개의 스레드(5명의 방문자)
가 사용하게 되는 것입니다.
즉, 임계구역은 상호 배제를 깨게 되지만, 자원 자체에서는 상호 배제를 유지할 수 있는 것입니다.
세마포어와 뮤텍스의 차이
세마포어
는뮤텍스
가 될 수 있지만,뮤텍스
는세마포어
가 될 수 없습니다.뮤텍스
는스레드
에서Lock
을 가지고 있기 때문입니다.
-
세마포어
는 소유할 수 없으며,뮤텍스
는 소유할 수 있고 소유주가 그에 대한 책임을 집니다. -
뮤텍스
의 경우뮤텍스
를 소유하고있는 스레드가 이뮤텍스
를 해제할 수 있습니다. 하지만,세마포어
는 소유하지 않고 있는스레드
가세마포어
를 해제할 수 있습니다. -
세마포어
는 시스템 범위에 걸쳐있고 파일 시스템 상의 파일 형태로 존재합니다. 하지만,뮤텍스
는 프로세스 범위를 가지고 프로그램이 종료될 때 자동으로 지워집니다. 세마포어
는 동기화 대상이 여러개 일 때,뮤텍스
는 동기화 대상이 오로지 하나 일 때 사용됩니다.
모니터(Monitor)
세마포어
의 경우 오래된 동기화 도구입니다. 자바 프로그램에서는 모니터에 대한 활용이 높습니다. 세마포어
가 어셈블리 언어에 적합한 도구라면 모니터
는 그보다 고수준인 언어의 도구라고 할 수 있다.
모니터
의 경우 두 개의 queue
가 있는데 각각 배타동기
와 조건동기
의 역할을 합니다.
배타동기
배타동기
의 queue
는 하나의 스레드
만 공유자원에 접근할 수 있게 하는 작용을 하는 공간입니다. 특정 스레드
가 공유자원을 사용하는 함수를 사용하고 있으면 다른 스레드
는 접근을 할 수 없고 대기해야 합니다.
조건동기
조건 동기
의 queue
는 진입 스레드
가 블록
되면서 새 스레드가 진입가능하게 하는 공간입니다. 새 스레드
는 조건동기
로 블록된 스레드를 깨울 수 있습니다. 깨워진 쓰레드는 현재 쓰레드가 나가면 재진입할 수 있습니다.
모니터의 원리
자바의 모든 객체는 모니터가 될 수 있습니다. 배타 동기
는 synchronized
키워드를 사용해서 지정할 수 있고 조건 동기
는 wait()
함수와 notify()
함수, notifyAll()
함수를 사용합니다. 배타 동기
를 지정하는 함수들은 공통 자원을 사용하고 있는 경우입니다. 위의 흐름을 보면 모니터
는 하나의 프로세스(애플리케이션)내에 다른 스레드 간에 동기화할 때 사용된다는 것을 알 수 있습니다.
-
synchronized : 이 키워드를 적어주기만 하면
상호배타
의 원리를 만족시키는 함수로 만들어줍니다. -
wait() : 이 함수를 실행하면 진입한 스레드를 조건 동기
queue
에블록
을 시킵니다. -
notify() : 이 함수는 그렇게
블록
된 함수를 깨우는데, 새로운 스레드가 실행하는 방식으로 깨우게 됩니다. -
notifyAll() : 이 함수는 모든 스레드를 깨우는 것으로 사용할 수 있습니다.
의문점
notifyAll()
은 왜 필요할까요? 모니터의 경우 세마포어
처럼 여러 자원을 이용할 수도 없을 텐데??
그 이유는 스레드
가 notify()
를 기다리는 이유가 제각각이기 때문입니다.
예를 들어, 특정 작업이 완료되기를 기다리는 스레드
가 있을 수 있기 때문에 이런 경우에 작업이 완료되면 모든 대기 스레드가 비즈니스를 계속할 수 있습니다. (이 때, notifyAll () 을 사용 하여 대기중인 모든 스레드를 동시에 깨울 수 있습니다.)
세마포어와 모니터의 차이
세마포어
를 사용할 때는 애플리케이션에서 스레드
가 종료될 때 락
을 해제하는 부분에 주의를 기울여야 합니다. 그렇지 않으면 그 공유자원
을 써야 하는 다른 어떤 스레드
도 더 이상 진행을 할 수 없는 상태에 이르게 됩니다. 그리고 그 공유자원
을 액세스 해야 하는 모든 루틴에서 그 자원을 사용하기 전에 명시적으로 락
을 획득해야만 하는데, 코딩하다 보면 가끔 빼먹는 일도 자주 일어납니다.
즉, 모니터
는 공유자원에 접근할 수 있는 키의 획득과 해제를 모두 처리해서 간단하지만 세마포어
는 직접 키해제와 공유자원 접근 처리를 해주어야 한다는 것입니다.
참고 : http://daplus.net/java-%EC%9E%90%EB%B0%94-notify-%EB%8C%80-notifyall-%EB%8B%A4%EC%8B%9C/
https://about-myeong.tistory.com/34
https://www.youtube.com/channel/UCWpCGcAr-4jQGLwmjTV83tA (질문에 답변을..!!)
댓글남기기