Operating System : 뮤텍스(Mutex) / 세마포어(Semaphore) / 모니터(Monitor)

뮤텍스(Mutex) / 세마포어(Semaphore) / 모니터(Monitor)

뮤텍스(Mutex) ,세마포어(Semaphore), 모니터(Monitor) 전부 운영체제의 상호배제(Mutual Exclusion) 동기화 기법입니다.

뮤텍스(Mutex)

뮤텍스(Mutex)는 상호배제(MUTual EXclusion)의 머릿글자를 따서 만들어졌습니다. 0또는 1의 값을 가지는 이진 세마포어와 유사합니다. Critical Section (임계구역)을 가진 스레드들의 실행 시간을 서로 겹치지 않게 단독으로 실행하게 하는 기술입니다. 다른 프로세스(애플리케이션)간에 동기화할 때 사용할 수 있습니다.

  • 프로세스들의 공유 리소스에 대한 접근을 조율하기 위해 LockingUnlocking을 사용합니다.

  • 뮤텍스 객체를 두 스레드가 동시에 사용할 수 없습니다.

예시

일부 음식점들은 공용 화장실(공유 자원) 관리 차원에서 화장실을 잠궈두고(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진입 스레드블록되면서 새 스레드가 진입가능하게 하는 공간입니다. 스레드조건동기로 블록된 스레드를 깨울 수 있습니다. 깨워진 쓰레드는 현재 쓰레드가 나가면 재진입할 수 있습니다.

모니터의 원리

img


img


img

자바의 모든 객체는 모니터가 될 수 있습니다. 배타 동기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 (질문에 답변을..!!)

댓글남기기