백엔드 개발자

뮤텍스, 세마포어, 데드락 본문

CS/운영체제

뮤텍스, 세마포어, 데드락

임잠탱 2024. 12. 12. 19:58

레이스 컨디션(Race Condition)과 동기화 기법의 필요성

레이스 컨디션은 여러 스레드가 동일한 자원에 동시에 접근하거나 작업을 수행할 때 발생하는 동기화 문제다. 각 스레드의 실행 순서에 따라 매번 결과가 달라질 수 있어 데이터 무결성이 깨지거나 의도치 않은 동작이 발생할 수 있다.

동기화 기법 Lock

멀티스레드 환경이나 멀티프로세스 시스템에서는 여러 작업이 동일한 자원에 동시에 접근할 경우 데이터 일관성이 깨지거나 충돌이 발생할 수 있다(Race Condition 문제). 이를 방지하기 위해 동기화(Synchronization) 기법이 필요하며, 이 중 가장 널리 사용되는 것이 바로 Lock 기법이다.

Lock은 특정 자원에 대한 접근 권한을 하나의 스레드나 프로세스가 독점적으로 가지도록 보장하여 충돌을 방지한다. 락을 사용하는 방식에는 여러 종류가 있으며, 각각의 특성과 사용 사례가 다르다.


스핀락(Spin Lock)

스핀락은 이름처럼 계속 무한루프를 돌며 락의 상태를 확인하는 방식이다. 이는 대기 시간이 짧을 것으로 예상될 때 유용하지만, 대기가 오래 걸릴 경우, 계속 무한루프를 돌며 CPU를 소모하기 때문에 비효율적일 수 있다.

스핀락의 동작 방식

  • 락이 해제될 때까지 루프를 돌면서 상태를 확인 (busy-waiting).
  • 락이 해제되면 즉시 자원을 사용 가능.

장점

  • 대기 시간이 짧은 경우 성능이 뛰어남.
  • 문맥 전환(Context Switching)이 발생하지 않아 오버헤드가 적음.

단점

  • 락을 오래 기다릴 경우 CPU 자원을 낭비.
  • 단일 코어 환경에서는 비효율적.

스핀락의 자원 사용 단점과 고급 락 기법

스핀락은 짧은 대기 시간에는 유용하지만, 대기 시간이 길거나 자원을 효과적으로 분배해야 하는 경우에는 적합하지 않, 이러한 단점을 해결하기 위해 고급 락 기법들이 사용된다. 대표적인 예로 뮤텍스(Mutex)와 세마포어(Semaphore)가 있다.


뮤텍스(Mutex)

뮤텍스(Mutual Exclusion)는 상호 배제를 보장하는 락으로, 하나의 스레드만 특정 자원에 접근할 수 있도록 제한한다. 뮤텍스는 스핀락과 달리 자원이 사용 중일 때 대기 상태로 전환되어 CPU 자원을 절약한다.

특징

  • 배타적 접근: 한 번에 하나의 스레드만 접근 가능.
  • 블로킹 방식: 락을 사용할 수 없을 때 스레드를 대기 상태로 만듦.
  • OS 지원: 커널 수준에서 구현되며, 프로세스 간 동기화도 가능.

사용 사례

  • 단일 자원 보호: 파일 읽기/쓰기, 메모리 접근 등.
  • 프로세스 간 동기화: 여러 프로세스가 공유 메모리를 사용할 때.

세마포어(Semaphore)

세마포어는 동시 접근 가능한 스레드 수를 제한하는 동기화 기법이다. 접근 가능한 스레드 수가 1개 인 경우에는 이진 세마포어(Binary Semaphore), 그 외는 카운팅 세마포어(Counting Semaphore)라고 한다. 이진 세마포어는 뮤텍스와 유사한 방식으로 작동하지만, 카운팅을 증가/감소 시키는 행위에 집중하여 락을 획득한 스레드가 아닌 다른 스레드가 락을 해제할 수 있다.

특징

  • 동시성 제어: 자원의 접근 가능한 개수를 설정.
  • 카운트 방식: 세마포어의 초기값이 자원 개수를 나타냄.
  • 블로킹 방식: 자원이 부족하면 대기 상태로 전환.

사용 사례

  • 리소스 풀 관리: 데이터베이스 커넥션 풀, 네트워크 연결.
  • 생산자-소비자 문제: 제한된 버퍼에서 데이터 생성과 소비 동기화.

코드 예시 (Java)

Semaphore semaphore = new Semaphore(3); // 동시에 3개까지 접근 가능

semaphore.acquire(); // 접근 권한 획득
try {
    // Critical Section
} finally {
    semaphore.release(); // 접근 권한 반환
}

뮤텍스와 세마포어의 차이

구분뮤텍스(Mutex)세마포어(Semaphore)

접근 가능한 스레드 수 한 번에 1개 여러 개 (카운트로 관리)
주요 목적 상호 배제 (Mutual Exclusion) 동시성 제어 (Concurrency Control)
동작 방식 락을 소유한 스레드만 해제 가능 락 해제는 어느 스레드든 가능

모니터 락(Monitor Lock)

모니터 락은 객체 단위로 동기화를 제공하는 고수준 락 기법으로, 언어 차원에서 지원된다. 예를 들어, Java의 synchronized 키워드가 이에 해당합니다.


데드락(Deadlock)

데드락은 두 개 이상의 스레드가 서로의 자원을 기다리며 무한히 대기 상태에 빠지는 현상을 의미한다.

데드락 발생 조건 4 가지

  1. 상호 배제(Mutual Exclusion): 자원은 한 번에 하나의 프로세스만 사용 가능.
  2. 점유 대기(Hold and Wait): 자원을 점유한 상태에서 추가 자원을 요청.
  3. 비선점(No Preemption): 자원을 강제로 빼앗을 수 없음.
  4. 순환 대기(Circular Wait): 자원을 기다리는 프로세스 간에 순환 구조가 존재.

위 4가지 조건을 모두 충족하면 데드락이 발생한다.

데드락 방지, 회피, 복구 방법

1. 데드락 방지

위 4가지 조건 중 하나라도 충족되지 않으면 발생하지 않는다.

  • 순서 정하기: 자원을 항상 정해진 순서로 요청. (오름차순으로 1, 4 순으로 요청은 가능하지만 4, 1 순으로 요청이 불가하도록 하여 순환 방지)
  • 자원 점유 제한: 점유 상태에서 추가 자원 요청 금지. (점유 대기 방지)
  • 필요한 자원을 한 번에 모두 얻고 시작하기 (점유 대기 방지) => 비효율적

2. 데드락 회피

  • 은행원 알고리즘(Banker's Algorithm): 시스템 상태를 사전에 분석하여 안전 여부 판단. 데드락이 발생할 것 같은지 검사

3. 데드락 탐지 및 복구

  • 프로세스 강제 종료: 데드락에 포함된 프로세스를 종료.
  • 자원 선점: 자원을 강제로 해제하여 다른 프로세스에 할당.

데드락 탐지 방법

  • 자원 할당 그래프(Resource Allocation Graph):
    • 자원과 프로세스를 노드로 표현하고, 자원 요청과 할당 관계를 간선으로 나타냄.
    • 순환(Cycle)이 발견되면 데드락이 발생한 것으로 판단.
  • Wait-For 그래프(Wait-For Graph):
    • 프로세스 간의 대기 관계를 표현하는 그래프.
    • 순환 구조가 존재하면 데드락 발생.

락 성능 최적화 기법

1. 락 경합(Contention) 감소

  • 락 경합이 높은 경우, 데이터를 여러 부분으로 나누어 각기 다른 락을 사용.
  • 예: Striped Lock 기법.

2. 락 시간 최소화

  • 락을 거는 범위를 최소화하여 병렬성을 극대화.

3. 비동기 프로그래밍

  • 락 대신 비동기 작업을 활용하여 동기화를 회피.
  • 예: Java의 CompletableFuture, Node.js의 이벤트 루프.

 

'CS > 운영체제' 카테고리의 다른 글

가상메모리  (0) 2024.12.05
프로세스 & 스레드  (0) 2024.11.28
Comments