본문 바로가기

취업과 기본기 튼튼/빽 투더 기본기

빽 투더 기본기 [OS 5편]. 뮤텍스와 세마포어

이 글에서는 저번 글에 이어, 동기화 기법 중 하나인 뮤텍스와 세마포어에 대해 적어본다.

1. 뮤텍스 (MUTual Exclusion)

1.1. 뮤텍스란?

뮤텍스는 상호배재라는 뜻으로, 이전 글에서와 마찬가지로 동기화 기법 중 하나이다.
뮤텍스는, 쓰레드 간 임계 영역의 동기화를 위한 기법이다.

1.2. 어떻게 구현하는가?

lockunlock 의 개념이 등장한다.
임계 영역에 먼저 들어가는 쓰레드가 lock 을 걸면, 이 쓰레드가 unlock 을 할 때 까지, 다른 쓰레드들은 임계 영역에 들어가지 못하도록 하는 것이다.
즉, 임계 영역에 들어가는 쓰레드는 임계 영역 앞뒤에 lockunlock 을 해야한다.

v = 1;
def lock():
    while v != 1
            # 2. 이미 다른 쓰레드에 의해 선점된 경우, v=0 이므로, 이 루프를 계속 돈다.
        if (v==1)
            # 4. 앞서 선점한 쓰레드가 락을 풀면 v=1 이므로, 루프를 탈출한다. 
            break;
    # 1. 먼저 선점한 쓰레드가 v=0 으로 만들어, 락을 잠가버린다.
    v = 0;

def unlock():
    # 3. 할 일을 하고나온 쓰레드는 v=1 로 만들어, 락을 푼다.
    v = 1;
lock() # 들어갈 때 락을 잠그고
# critical section
unlock() # 나갈 때 락을 푼다.

2. 세마포어 (Semaphore)

2.1. 세마포어란?

뮤텍스와 마찬가지로, 동기화 기법 중 하나다.
다만, 뮤텍스는 임계 영역에 들어가는 쓰레드가 하나라면, 세마포어는 복수 개가 가능하다.

2.2. 어떻게 구현하는가?

waitsignal 의 개념이 등장한다.
일반적으로, wait 이 먼저 호출되어, 임계 영역에 들어갈 수 있는지 확인한다. 혹은, 먼저 실행되어야하는 프로세스가 실행되었는지를 확인한다. 조건에 만족하면, wait을 빠져나와 임계영역으로 들어간다.
이후 signal 이 호출되어, 임계 영역을 빠져나왔음을 알린다.

S = 3 # 임계 영역에 들어갈 수 있는 쓰레드, 프로세스는 3개다.
def wait(S):
  S--
  if S < 0:
    # add this process into Waiting Queue (Sleep or Block)

def signal(S):
  S++
  if S > 0:
    # pop the process from the Waiting Queue (Wake up)
wait(S)
# critical section
signal(S)

2.3. 데드락(Dead Lock) 문제

세마포어는 데드락 문제가 있는데, 예를 들면 다음과 같은 상황이다.

P0                  P1
wait(S);           wait(Q);
wait(Q);           wait(S);
...                   ...
signal(S);        signal(Q);
signal(Q);        signal(S);

각 프로세스의 첫째줄이 동시에 실행될 경우, 서로 wait 상태로, 다른 쪽에서 signal 을 해주기 전까지 기다리게 되는데, 둘 다 모두 계속 wait 에 머물러 있으므로, 프로그램은 절대 끝나지 않는다. 이 현상이 데드락(교착상태) 다.

따라서, 세마포어를 쓸 때는 이와 같은 문제를 유념해두고 사용해야한다.

3. 뮤텍스와 세마포어의 차이

이건… 면접의 흔한 질문이라고 한다. 검색해보면 이 내용에 대한게 많다.
아무튼 정리를 해보면.. 가장 큰 차이점은 이거라고 한다.

세마포어는 뮤텍스가 될 수 있지만 (S = 1 인 경우), 뮤텍스는 세마포어가 될 수 없다.
뮤텍스는 바이너리 값을 갖는 세마포어다.

지금까지 언급한 동기화 방법 외에도, 하드웨적 동기화, 모니터 등이 있지만, 생략하겠다.

참고