뮤텍스(Mutex) vs 세마포어(Semaphore) vs 스핀락(Spin Lock)

뮤텍스(Mutex) vs 세마포어(Semaphore) vs 스핀락(Spin Lock)

1. 뮤텍스, 세마포어, 스핀락은 왜 생겨났을까?

다중 프로그래밍이 가능해지면서 발생하는 문제는 공유자원을 여러 프로세스나 스레드가 사용하게 되어 데드락(교착 상태)이 자주 발생하게 되는 동기화 문제이다.

식사하는 철학자들 문제

교착상태(DeadLock)는 식사하는 철학자들 문제로 그 의미를 설명할 수 있다.

원형 식탁 가운데에 밥이 있고, 5명의 철학자들과 5개의 젓가락이 있다고 가정해보자. 철학자들이 밥을 먹으려면 자신의 양쪽에 있는 젓가락을 사용해야 한다. 이때 왼쪽 젓가락을 먼저 들어야 한다. 그리고 식사를 마치면 젓가락 두 개를 다시 내려놓는다.

만약, 철학자들이 동시에 배가 고프면 어떻게 될까? 모든 철학자들이 자신의 왼쪽에 있는 젓가락을 집게 될 것이다. 그러면 누가 밥 먹는 것을 포기할 떄까지 철학자들은 영원히 밥을 먹을 수 없고, 오른쪽 젓가락이 생길 때까지 무한정으로 기다리게 된다.

이를 바로 교착상태(DeadLock)라고 한다. 즉 교착상태(DeadLock)란 두 개 이상의 작업이 서로 상대방의 작업이 끝나기를 기다리는 상태로, 아무것도 완료하지 못하고 무한 대기 상태로 빠지게 되는 것을 말한다.

이렇게, 공유자원을 두 개 이상의 프로세스가 동시에 읽거나 쓰는 상황을 경쟁 상태(race condition)라고 한다.

동기화란, 동시에 공유 자원에 접근하는 것은 데이터의 일관성을 해칠 수 있기 때문에 프로세스들의 실행 순서를 정하여 공유 자원의 일관성을 보장하는 것을 말한다. 즉, 한 순간에 하나의 자원을 한 프로세스만 사용할 수 있도록 하는 것이다.

뮤텍스, 세마포어, 스핀락은 동기화 문제를 해결하기 위해 생겨난 것이다.

2. 임계영역 (Critical Section)

정의

스핀락, 세마포어, 뮤텍스에 대해 알기 전, 임계영역에 대해 이해하고 넘어가야 한다.

임계 영역이란, 프로세스들이 공유 자원을 접근할 때 문제가 발생하지 않도록 한 번에 하나의 프로세스만 이용할 수 있게 다른 프로세스의 접근을 제한하는 영역을 말한다.

조건

  • 상호 배제 (Mutual Exclusion)

하나의 프로세스가 임계 영역에서 실행중이라면, 다른 프로세스는 해당 영역에 접근할 수 없다.

  • 진행 (Process)

임계 영역에서 실행중인 프로세스가 없고, 임계 영역에 들어가고자 대기하는 프로세스가 여러개라면, 대기 중인 프로세스만 진입 후보가 될 수 있고 임계 영역에 들어갈 프로세스를 결정해주어야 한다.

  • 한정된 대기 (Bounded Waiting)

한 프로세스가 임계 영역에 진입하기 위해 요청을 하고 해당 요청이 받아들여지는 동안, 다른 프로세스들이 임계 영역에 진입하는 횟수는 제한이 있어야 한다. 이는 기아를 막기 위함이다.

기아 (Starvation)

낮은 우선순위를 가진 프로세스가 영원히 실행되지 않는 문제

3. 스핀락(Spin Lock)

image

정의

임계영역이 Lock이 걸려서 진입이 불가능할 때, 임계영역이 UnLock 되어 진입이 가능해질 때까지 루프를 돌면서 재시도하여 스레드가 CPU를 점유하고 있는 상태이다.

즉, 스레드는 무한 루프로 공유자원의 상태를 확인하고, Lock이 반환될 때까지 확인하여 대기한다.

특징

  • CPU를 점유하며 코드를 반복하면서 임계영역이 UnLock이 될 때까지 해당 코드를 무한으로 실행하는 상태이기 때문에 스핀락은 Busy Waiting 상태

Busy Waiting

  • 특정 공유자원에 대하여 이용 권한을 획득하기 위해 권한을 얻을 때까지 확인하는 것
  • CPU의 자원을 쓸데없이 낭비함
  • 스핀락은 운영체제의 스케줄링을 받지 않고 무한으로 실행되고 있기 때문에 문맥교환(context switching)이 이루어지지 않음
  • 문맥교환이 이루어지지 않기 때문에 멀티 코어 프로세서 시스템에서만 사용 가능
  • 스핀락은 상태가 오직 획득(Lock)/해제(UnLock) 만 존재하여 한 번에 하나의 컴포넌트만 접근이 가능하고, 획득과 해제의 주체는 동일해야함
  • 짧게 수행할 수 있는 작업에 주로 사용

장점

  • 문맥 교환이 이루어지지 않기 때문에 비용이 들지 않아 효율적임

단점

  • 임계영역이 오랫동안 언락되지 않으면 그 시간동안 계속 CPU를 차지해 다른 스레드는 CPU를 사용할 수 없어 오버헤드가 존재함

4. 뮤텍스(Mutex / Mutual Exclusion)

image

정의

뮤텍스란, 화장실 하나에 키가 하나인 경우라고 할 수 있다. 한 사람이 화장실 키를 가지고 화장실에 들어가 있다면, 화장실에 들어가고 싶은 사람들은 화장실을 사용하고 있는 사람이 키를 들고 나올 때까지 기다리고 있는 것이다.

즉, 임계구역이 Lock일 경우 스레드는 Sleep 상태로 대기하고 임계구역이 Unlock이 되면 Wakeup하여 뮤텍스 객체 접근 권한을 요청하는 것이다.

특징

  • 스핀락과 동일하게 상태를 획득/해제 만 존재
  • 임계영역에 락을 걸은 스레드만이 임계영역을 나갈 때 락을 해체할 수 있음
  • 시스템 전반에 영향을 주지 않고 길게 처리해야 하는 작업의 경우 주로 사용
  • 주로 스레드 작업에서 사용

5. 세마포어(Semaphore)

image

정의

공유자원 혹은 임계영역에 접근할 수 있는 프로세스나 스레드의 수를 지정하는 방법이다. 즉, 지정된 개수만큼 스레드가 공유자원에 동시에 접근할 수 있다.

프로세스나 스레드가 공유자원에 접근하고 싶을 경우, 세마포어의 값을 확인하고 변경하여 접근할 수 있다. 세마포어는 공통으로 관리하는 하나의 값(공유자원에 접근할 수 있는 스레드의 개수)을 이용하여 상호배제를 달성한다.

과정

  • 컴포넌트가 특정 자원에 접근할 때 semWait이 먼저 호출되어 임계영역에 들어갈 수 있는지 확인한다.
  • 임계영역에 접근이 가능하다면 semWait을 빠져나와 임계영역에 들어간다.
  • 이후 semSignal이 호출되어 임계영역을 빠져나온다.
  • semWait 연산 : 세마포어의 값 감소 / 값이 만약 음수가 되면 semWait을 호출한 스레드는 공유 자원을 이용할 수 없으므로 대키 큐에 넣어 block 됨
  • semSignal 연산 : 세마포어의 값 증가 / 값이 만약 양수가 아니라면 semWait 연산에 의해 블록된 스레드를 다시 wake 시킴

특징

  • 세마포어는 접근할 수 있는 프로세스의 수를 1로 지정함으로써 뮤텍스가 될 수 있다.
  • 세마포어는 자원 소유가 불가능하다.
  • 임계영역에 있지 않은 스레드도 세마포어를 해제할 수 있다. (뮤텍스의 경우, 임계영역에 있는 스레드만 뮤텍스를 해제할 수 있다.)

이진 세마포어

  • 0 또는 1 값만 가질 수 있는 세마포어
  • 임계구역 문제를 해결하는데 사용하며 자원이 하나이기 때문에 뮤텍스로도 사용할 수 있다.
  • 뮤텍스를 이진 세마포어라고 부르기도 한다.

계수 세마포어

  • 도메인이 0 이상인 임의의 정수값인 세마포어
  • 여러 개의 자원을 가질 수 있고, 제한된 자원을 가지고 액세스 작업을 할 때 사용

뮤텍스 vs 세마포어

[공유자원 획득 여부]

  • 뮤텍스: lock을 가지는 형태로 lock을 가지면, 공유 자원을 소유할 수 있다.
  • 세마포어: 신호 매커니즘으로 정수값(공유자원에 접근할 수 있는 스레드/프로세스의 수)을 이용하여 프로세의 리소스 해제 및 획득 여부를 관리할 수 있다.