Backend study/Backend theory

뮤텍스(Mutex)와 세마포어(Semaphore)

adulty22 2024. 9. 24. 23:07

뮤텍스(Mutex)세마포어(Semaphore)동시성 제어 기법으로, 여러 프로세스나 스레드가 공유 자원에 접근할 때 발생하는 경쟁 조건(race condition)을 방지하기 위해 사용된다. 이 두 개념은 동기화 문제를 해결하는 데 중요한 역할을 하며, 각기 다른 특성과 용도로 사용된다.

1. 뮤텍스(Mutex)

뮤텍스란?

  • MutexMutual Exclusion의 약자로, 상호 배제를 의미한다. 하나의 스레드프로세스만이 특정 시점에 공유 자원에 접근할 수 있도록 잠금(Lock)을 제공하는 동기화 도구이다.
  • 단일 사용자: 특정 공유 자원에 대해 동시에 하나의 스레드만 접근할 수 있다. 다른 스레드가 동일한 자원에 접근하려면, 먼저 사용 중인 스레드가 자원의 잠금을 해제해야 한다.

뮤텍스의 동작 원리

  • 잠금(Lock): 자원에 접근하기 전에 해당 자원을 잠근다. 잠금이 걸리면 다른 스레드는 그 자원에 접근하지 못하고 대기 상태가 된다.
  • 잠금 해제(Unlock): 자원의 사용이 끝나면 잠금을 해제하여 다른 스레드가 그 자원에 접근할 수 있게 한다.
  • 상호 배제: 한 스레드가 자원을 사용하는 동안 다른 스레드가 동시에 접근하는 것을 방지함으로써, 데이터 불일치데이터 손상을 방지한다.

뮤텍스의 특징

  • 소유권: 뮤텍스는 잠금을 설정한 스레드만 잠금을 해제할 수 있다. 즉, 잠금을 설정한 스레드만 자원의 사용을 끝내고 잠금을 해제할 수 있다.
  • 단일 잠금: 뮤텍스는 동시에 하나의 스레드만 자원을 사용할 수 있다. 여러 스레드가 동시에 접근하는 것은 불가능하다.
  • 경량: 뮤텍스는 일반적으로 빠르고 간단한 동기화 기법으로, 하나의 자원을 보호할 때 자주 사용된다.

뮤텍스 사용 예시 (Python)

import threading

# 공유 자원
counter = 0
# 뮤텍스 객체 생성
lock = threading.Lock()

def increment():
    global counter
    for _ in range(1000000):
        # 뮤텍스 잠금
        with lock:
            counter += 1

# 두 개의 스레드를 생성하여 동시에 실행
thread1 = threading.Thread(target=increment)
thread2 = threading.Thread(target=increment)

thread1.start()
thread2.start()

thread1.join()
thread2.join()

print(f"Final counter value: {counter}")

위 코드에서 lock 객체는 뮤텍스로 동작한다. 각 스레드는 with lock을 통해 자원에 잠금을 설정한 후 공유 자원에 접근한다. 이로 인해 두 스레드가 동시에 counter를 증가시키는 작업을 할 때 동기화 문제가 발생하지 않는다.

 

2. 세마포어(Semaphore)

세마포어란?

  • 세마포어(Semaphore)동기화 도구로, 정해진 수의 스레드나 프로세스만 동시에 특정 자원에 접근할 수 있게 제한하는 방식이다. 세마포어는 계수기(Counter)를 사용하여 자원에 접근할 수 있는 스레드 또는 프로세스의 최대 수를 제한한다.
  • 멀티 사용자 허용: 세마포어는 여러 개의 스레드가 동시에 자원에 접근할 수 있도록 허용한다. 예를 들어, 세마포어의 값이 3이라면, 최대 3개의 스레드가 동시에 자원에 접근할 수 있다.

세마포어의 동작 원리

  • 카운터: 세마포어는 내부적으로 카운터를 유지한다. 카운터의 값은 자원에 접근할 수 있는 스레드의 수를 나타낸다.
    • 세마포어의 초기 값은 자원에 접근할 수 있는 최대 스레드 수로 설정된다.
  • P(S) 연산(Wait/Acquire): 세마포어의 값을 감소시키는 연산이다. 세마포어의 값이 0보다 클 경우, 스레드는 자원에 접근할 수 있으며 세마포어 값을 감소시킨다. 만약 세마포어 값이 0이면, 스레드는 자원이 사용 가능할 때까지 대기한다.
  • V(S) 연산(Signal/Release): 세마포어의 값을 증가시키는 연산이다. 자원을 다 사용한 스레드는 세마포어 값을 증가시켜, 다른 스레드가 자원에 접근할 수 있도록 한다.

세마포어의 특징

  • 카운팅 세마포어: 세마포어의 값이 1 이상일 경우, 여러 스레드가 동시에 자원에 접근할 수 있다. 예를 들어, 값이 3이면 최대 3개의 스레드가 동시에 접근할 수 있다.
  • 바이너리 세마포어: 세마포어 값이 0 또는 1로만 설정되는 경우는 바이너리 세마포어라고 하며, 이 경우 뮤텍스처럼 동작한다. 단, 소유권 개념이 없으므로 잠금을 설정한 스레드 외에도 잠금을 해제할 수 있다.
  • 소유권 없음: 세마포어는 자원에 대한 소유권을 가지지 않기 때문에, 잠금을 설정한 스레드가 아닌 다른 스레드도 자원 해제를 할 수 있다.

세마포어 사용 예시 (Python)

import threading
import time

# 세마포어 객체 생성 (최대 3개의 스레드가 동시에 접근 가능)
semaphore = threading.Semaphore(3)

def task(n):
    # 세마포어 획득
    semaphore.acquire()
    print(f"Thread {n} is working...")
    time.sleep(2)  # 작업 수행
    print(f"Thread {n} is done.")
    # 세마포어 해제
    semaphore.release()

# 다수의 스레드 생성
threads = []
for i in range(6):
    t = threading.Thread(target=task, args=(i,))
    threads.append(t)
    t.start()

for t in threads:
    t.join()

위 예시에서 세마포어최대 3개의 스레드만 동시에 task 함수에 접근할 수 있게 제한한다. 총 6개의 스레드가 생성되지만, 한 번에 3개의 스레드만 작업을 수행하고, 나머지 스레드는 대기 상태로 있다가 이전 작업이 끝나면 세마포어에 의해 자원 접근이 허용된다.

 

3. 뮤텍스와 세마포어의 비교

특징  뮤텍스(Mutex) 세마포어(Semaphore)
동작 방식 자원에 대한 단일 스레드의 잠금을 보장 여러 스레드가 동시에 자원에 접근할 수 있음
잠금 상태 자원이 잠겨 있으면 다른 스레드는 대기 세마포어 값이 0이 될 때까지 대기
소유권 잠금한 스레드만 잠금을 해제할 수 있음 소유권 개념이 없으며, 누구든지 해제 가능
동시 접근 가능성 한 번에 하나의 스레드만 접근 가능 여러 개의 스레드가 동시에 접근 가능
사용 사례 단일 자원 보호: 예를 들어 공유 변수나 파일 제한된 자원 보호: 예를 들어 데이터베이스 연결
카운터 카운터 없음, 단일 잠금 카운터로 접근 가능한 스레드 수 제어

 

4. 뮤텍스와 세마포어의 사용 사례

뮤텍스 사용 사례

  • 공유 변수 보호: 스레드가 동시에 공유 변수에 접근할 때, 뮤텍스를 사용하여 단일 스레드만 해당 변수를 읽고 수정할 수 있도록 보호한다.
  • 파일 입출력: 여러 스레드가 동시에 파일에 접근해 읽거나 쓸 때, 뮤텍스를 사용해 파일의 일관성을 유지한다.

세마포어 사용 사례

  • 데이터베이스 연결 제한: 데이터베이스 연결의 최대 수를 제한할 때, 세마포어를 사용해 여러 클라이언트가 동시에 제한된 수의 연결에만 접근할 수 있도록 제어한다.
  • 제한된 리소스: 예를 들어, 네트워크 포트나 프린터처럼 동시 접근할 수 있는 수가 제한된 자원에 접근할 때, 세마포어를 사용하여 허용 가능한 최대 접근 수를 제어한다.

 

  • 뮤텍스(Mutex)단일 스레드만 자원에 접근하도록 제어하는 동기화 도구이다. 주로 단일 자원에 대한 상호 배제를 보장하여 동기화 문제를 해결하는 데 사용된다.
  • 세마포어(Semaphore)여러 스레드가 동시에 자원에 접근할 수 있도록 하며, 자원에 대한 동시 접근 가능 스레드 수를 제어하는 데 사용된다. 카운팅 세마포어는 여러 개의 스레드가 동시에 자원을 사용할 수 있지만, 제한된 자원을 보호하는 데 유용하다.

이 두 동기화 기법은 프로세스와 스레드가 동시에 접근할 수 있는 공유 자원을 안전하게 보호하고, 경쟁 상태를 방지하는 데 필수적이다.

728x90