-
임계 구역(Critical Section)
-
상호 배제(Mutual Exclusion)
-
뮤텍스(Mutex)
-
특징
-
뮤텍스(Mutex) – ReentrantLock 사용
-
요약 설명
-
장단점
-
세마포어(Semaphore)
-
구성 요소
-
세마포어(Semaphore) – Semaphore 사용
-
요약 설명
-
세마포어의 종류
-
특징
-
뮤텍스와 세마포어의 차이
-
정리
-
참고하면 좋은 영상
-
질문이 들어온다면?
-
1. "뮤텍스와 세마포어의 차이를 설명해주세요."
-
2. "뮤텍스를 사용하는 예시를 들어주세요."
-
3. "세마포어는 어떤 상황에서 더 적합한가요?"
-
4. "뮤텍스를 잘못 사용하면 발생할 수 있는 문제는 무엇인가요?"
-
5. "세마포어를 잘못 구현했을 때 발생할 수 있는 대표적인 동시성 문제는요?"
뮤텍스와 세마포어에 대해서 정리를 해보자.
하지만 그 전에 임계 구역과 상호 배제에 대해서 알아보면서 뮤텍스와 세마포어에 대해서 정리를 해보자.
임계 구역(Critical Section)
임계 구역이란 공유 자원(Shared Resource)에 접근하는 코드 영역을 말한다. 여러 프로세스나 스레드가 동시에 실행되는 환경에서 공유 자원을 동시에 수정하거나 접근할 경우, 데이터의 일관성이 깨지거나 예기치 못한 오류가 발생할 수 있다. 이를 Race Condition(경쟁 상태)라고 하며, 이 문제를 방지하기 위해 임계 구역을 정의한다.
임계 구역에서는 한 번에 하나의 프로세스/스레드만 접근할 수 있어야 하며, 이를 보장하는 것이 바로 상호 배제(Mutual Exclusion)이다.
상호 배제(Mutual Exclusion)
상호 배제란, 동시에 둘 이상의 프로세스나 스레드가 임계 구역에 진입하지 못하도록 제어하는 기법이다. 이를 통해 동기화(Synchronization) 문제를 해결하고, 공유 자원의 무결성과 일관성을 유지할 수 있다.
상호 배제를 구현하기 위해 대표적으로 사용하는 기법이 바로 뮤텍스(Mutex)와 세마포어(Semaphore)이다.
뮤텍스(Mutex)

뮤텍스(Mutual Exclusion Object)는 임계 구역에 하나의 스레드만 접근하도록 보장하는 락(Lock) 객체이다. 뮤텍스를 획득한 스레드만 공유 자원에 접근할 수 있으며, 작업이 끝난 후 반드시 뮤텍스를 해제해야 한다.
특징
- Binary 상태: 뮤텍스는 항상 잠김(Locked) 또는 풀림(Unlocked)의 두 가지 상태만 가진다.
- 소유권이 존재함: 뮤텍스를 획득한 스레드만 해제할 수 있다. 다른 스레드는 해당 뮤텍스를 해제할 수 없다.
- 스레드 간 보호: 일반적으로 하나의 프로세스 내에서 여러 스레드 사이의 동기화를 위해 사용된다.
뮤텍스(Mutex) – ReentrantLock 사용
import java.util.concurrent.locks.ReentrantLock;
public class MutexExample {
// 공유 자원
private static int counter = 0;
// 뮤텍스 역할을 할 ReentrantLock 객체
private static final ReentrantLock lock = new ReentrantLock();
public static void main(String[] args) {
// 두 개의 스레드 생성
Thread t1 = new Thread(MutexExample::increment);
Thread t2 = new Thread(MutexExample::increment);
t1.start();
t2.start();
try {
t1.join(); // 메인 스레드는 t1 종료까지 대기
t2.join(); // 메인 스레드는 t2 종료까지 대기
} catch (InterruptedException e) {
e.printStackTrace();
}
// 최종 결과 출력
System.out.println("최종 counter 값: " + counter);
}
// 공유 자원에 접근하는 메서드 (임계 구역)
private static void increment() {
for (int i = 0; i < 10000; i++) {
lock.lock(); // 뮤텍스 획득
try {
counter++; // 임계 구역 – 공유 자원 수정
} finally {
lock.unlock(); // 반드시 해제해야 데드락 방지
}
}
}
}
요약 설명
- ReentrantLock은 Java에서 뮤텍스로 자주 사용하는 클래스이다.
- lock()을 호출한 스레드만 임계 구역에 진입할 수 있으며, 작업 후 반드시 unlock() 해야 한다.
- 위 코드에서 두 스레드가 동시에 counter를 증가시켜도 정확하게 20000이 출력된다.

장단점
장점
- 구현이 단순하고 직관적이다.
- 상호 배제 보장이 확실하다.
단점
- 데드락(Deadlock)의 위험이 존재한다.
- 우선순위 역전(Priority Inversion) 문제가 발생할 수 있다.
세마포어(Semaphore)

세마포어는 정수 값을 가지는 동기화 객체로, 동시에 접근할 수 있는 프로세스 또는 스레드의 수를 제어한다. 주로 카운팅 세마포어(Counting Semaphore)와 이진 세마포어(Binary Semaphore)로 구분된다.
구성 요소
- 정수 값(S): 초기값으로 접근 가능한 자원의 수를 나타냄
- 두 가지 기본 연산:
- wait() 또는 P() 또는 down()
→ 세마포어 값을 1 감소시킴. 값이 0보다 작아지면 블로킹 - signal() 또는 V() 또는 up()
→ 세마포어 값을 1 증가시킴. 대기 중인 프로세스가 있으면 깨움
- wait() 또는 P() 또는 down()
세마포어(Semaphore) – Semaphore 사용
import java.util.concurrent.Semaphore;
public class SemaphoreExample {
// 동시에 접근 가능한 최대 스레드 수: 3
private static final Semaphore semaphore = new Semaphore(3);
public static void main(String[] args) {
// 10개의 작업 스레드 생성
for (int i = 1; i <= 10; i++) {
int threadNum = i;
new Thread(() -> accessResource(threadNum)).start();
}
}
private static void accessResource(int threadNum) {
try {
// 세마포어 획득 시도 (자원이 없으면 대기)
semaphore.acquire();
System.out.println("Thread " + threadNum + " → 자원 접근 중");
// 자원 처리 시뮬레이션 (2초)
Thread.sleep(2000);
System.out.println("Thread " + threadNum + " → 자원 반환");
} catch (InterruptedException e) {
e.printStackTrace();
} finally {
// 세마포어 해제 (자원 반환)
semaphore.release();
}
}
}
요약 설명
- Semaphore(3) → 동시에 3개 스레드만 접근할 수 있도록 제한
- acquire() → 자원을 획득 (없으면 대기)
- release() → 자원을 반환 (다음 스레드에 기회 제공)
- 이 코드를 실행하면, 10개의 스레드 중 3개만 동시에 실행되며, 나머지는 대기 후 순차적으로 자원을 사용한다.

세마포어의 종류
- 카운팅 세마포어 (Counting Semaphore)
- 값이 0보다 크거나 같은 정수를 가짐
- 동시 접근 가능한 자원 수를 제어
- 예: 프린터 3대 → 세마포어 초기값을 3으로 설정
- 이진 세마포어 (Binary Semaphore)
- 0 또는 1의 값만 가짐
- 뮤텍스처럼 동작하지만 소유권이 없음
- 일반적으로 프로세스 간 상호 배제에 사용
특징
- 소유권 없음: 세마포어는 소유 개념이 없으므로, wait()를 호출한 프로세스가 아닌 프로세스가 signal()을 호출해도 문제가 되지 않는다.
- 프로세스 간 동기화 가능: 세마포어는 프로세스 간 IPC(Inter-Process Communication) 방식으로도 사용 가능하다.
- 더 일반화된 개념: 뮤텍스보다 유연한 동기화 제어가 가능하다.
뮤텍스와 세마포어의 차이
항목 뮤텍스 (Mutex) 세마포어 (Semaphore)
상태 | Binary (0 or 1) | Counting (≥ 0) |
소유권 | 있음 | 없음 |
사용 범위 | 스레드 간 동기화 | 프로세스/스레드 간 동기화 |
해제 가능 여부 | 락을 획득한 스레드만 해제 가능 | 어떤 스레드든 signal 가능 |
사용 목적 | 상호 배제 | 상호 배제 및 동기화 |
데드락 가능성 | 있음 | 있음 |
정리
- 임계 구역은 공유 자원을 사용하는 코드 영역이며, 경쟁 상태를 피하기 위해 보호해야 한다.
- 상호 배제는 임계 구역의 동시 접근을 막는 기법이다.
- 뮤텍스는 소유권이 있는 락을 통해 하나의 스레드만 임계 구역에 접근하게 한다.
- 세마포어는 정수 기반의 동기화 도구로, 자원 접근 수를 제어하거나, 프로세스 간 통신 및 순서를 조절하는 데도 사용된다.
- 뮤텍스는 주로 스레드 동기화, 세마포어는 프로세스/스레드 모두에 쓰이며 더 일반화된 개념이다.
참고하면 좋은 영상
https://www.youtube.com/watch?v=NL9JQh5bbZ8
질문이 들어온다면?
1. "뮤텍스와 세마포어의 차이를 설명해주세요."
뮤텍스는 하나의 스레드만 임계 구역에 접근할 수 있도록 하는 동기화 객체이며, 소유권 개념이 있어 락을 획득한 스레드만 해제할 수 있습니다. 반면 세마포어는 여러 스레드가 접근할 수 있도록 허용하며, 주로 리소스의 수를 관리하는 데 사용됩니다. 뮤텍스는 binary(0 또는 1) 개념인 반면, 세마포어는 counting 방식으로 동작합니다. 또한 세마포어는 소유권 개념이 없기 때문에 다른 스레드가 해제하는 것도 가능합니다. 요약하자면, 뮤텍스는 상호배제를, 세마포어는 리소스 제어와 동기화를 위한 도구입니다.
2. "뮤텍스를 사용하는 예시를 들어주세요."
뮤텍스는 다중 스레드 환경에서 공유 자원에 대한 동시 접근을 방지할 때 사용됩니다. 예를 들어, 여러 스레드가 동시에 로그 파일을 쓰는 상황에서 뮤텍스를 이용해 한 번에 하나의 스레드만 접근하도록 제한할 수 있습니다. 이를 통해 Race Condition을 방지하고, 데이터 일관성을 보장할 수 있습니다. Java에서는 ReentrantLock, C++에서는 std::mutex 같은 클래스로 구현할 수 있습니다.
3. "세마포어는 어떤 상황에서 더 적합한가요?"
세마포어는 제한된 개수의 리소스를 여러 스레드가 공유해야 할 때 적합합니다. 예를 들어, 데이터베이스 연결 풀처럼 동시에 최대 10개의 연결만 허용해야 하는 경우, 세마포어의 초기값을 10으로 설정해 접근을 제어할 수 있습니다. 또한 생산자-소비자 문제처럼 순서를 보장하며 동기화가 필요한 상황에서도 유용합니다. 뮤텍스는 단일 자원 보호에 초점이 맞춰져 있지만, 세마포어는 그보다 유연하게 리소스 수를 관리할 수 있습니다.
4. "뮤텍스를 잘못 사용하면 발생할 수 있는 문제는 무엇인가요?"
뮤텍스를 잘못 사용하면 데드락이 발생할 수 있습니다. 예를 들어, 두 스레드가 서로가 가진 락을 기다리는 상황이 되면 프로그램이 영원히 멈춥니다. 또한, 락을 획득한 스레드가 예외로 인해 unlock을 수행하지 않으면 다른 스레드가 영원히 대기하게 됩니다. 이러한 문제는 락 해제를 finally 블록에 넣거나 try-with-resources 패턴을 사용하는 것으로 예방할 수 있습니다.
5. "세마포어를 잘못 구현했을 때 발생할 수 있는 대표적인 동시성 문제는요?"
세마포어를 잘못 구현하면 자원 고갈(Starvation), 데드락, 우선순위 역전(Priority Inversion) 같은 문제가 발생할 수 있습니다. 예를 들어, wait() 호출만 반복하고 signal()을 누락하면 리소스가 반환되지 않아 모든 스레드가 블로킹될 수 있습니다. 또한 signal 순서가 잘못되면 의도한 동기화 흐름이 깨져 예기치 않은 동작을 초래합니다. 정확한 초기값 설정과 signal/wait 짝을 맞추는 것이 매우 중요합니다.
'Computer Science > OperatingSystem' 카테고리의 다른 글
[OS] DeadLock(교착상태) (0) | 2025.03.13 |
---|---|
[OS] 운영체제란? (0) | 2025.03.06 |
[OS] 컨텍스트 스위칭이란?(Context Swiching) (CS스터디) (0) | 2023.07.07 |
[OS] 프로세스와 스레드는 어떤 차이점이 있나요? (0) | 2023.06.30 |
[OS] 요구 페이징 (0) | 2023.04.19 |
뮤텍스와 세마포어에 대해서 정리를 해보자.
하지만 그 전에 임계 구역과 상호 배제에 대해서 알아보면서 뮤텍스와 세마포어에 대해서 정리를 해보자.
임계 구역(Critical Section)
임계 구역이란 공유 자원(Shared Resource)에 접근하는 코드 영역을 말한다. 여러 프로세스나 스레드가 동시에 실행되는 환경에서 공유 자원을 동시에 수정하거나 접근할 경우, 데이터의 일관성이 깨지거나 예기치 못한 오류가 발생할 수 있다. 이를 Race Condition(경쟁 상태)라고 하며, 이 문제를 방지하기 위해 임계 구역을 정의한다.
임계 구역에서는 한 번에 하나의 프로세스/스레드만 접근할 수 있어야 하며, 이를 보장하는 것이 바로 상호 배제(Mutual Exclusion)이다.
상호 배제(Mutual Exclusion)
상호 배제란, 동시에 둘 이상의 프로세스나 스레드가 임계 구역에 진입하지 못하도록 제어하는 기법이다. 이를 통해 동기화(Synchronization) 문제를 해결하고, 공유 자원의 무결성과 일관성을 유지할 수 있다.
상호 배제를 구현하기 위해 대표적으로 사용하는 기법이 바로 뮤텍스(Mutex)와 세마포어(Semaphore)이다.
뮤텍스(Mutex)

뮤텍스(Mutual Exclusion Object)는 임계 구역에 하나의 스레드만 접근하도록 보장하는 락(Lock) 객체이다. 뮤텍스를 획득한 스레드만 공유 자원에 접근할 수 있으며, 작업이 끝난 후 반드시 뮤텍스를 해제해야 한다.
특징
- Binary 상태: 뮤텍스는 항상 잠김(Locked) 또는 풀림(Unlocked)의 두 가지 상태만 가진다.
- 소유권이 존재함: 뮤텍스를 획득한 스레드만 해제할 수 있다. 다른 스레드는 해당 뮤텍스를 해제할 수 없다.
- 스레드 간 보호: 일반적으로 하나의 프로세스 내에서 여러 스레드 사이의 동기화를 위해 사용된다.
뮤텍스(Mutex) – ReentrantLock 사용
import java.util.concurrent.locks.ReentrantLock;
public class MutexExample {
// 공유 자원
private static int counter = 0;
// 뮤텍스 역할을 할 ReentrantLock 객체
private static final ReentrantLock lock = new ReentrantLock();
public static void main(String[] args) {
// 두 개의 스레드 생성
Thread t1 = new Thread(MutexExample::increment);
Thread t2 = new Thread(MutexExample::increment);
t1.start();
t2.start();
try {
t1.join(); // 메인 스레드는 t1 종료까지 대기
t2.join(); // 메인 스레드는 t2 종료까지 대기
} catch (InterruptedException e) {
e.printStackTrace();
}
// 최종 결과 출력
System.out.println("최종 counter 값: " + counter);
}
// 공유 자원에 접근하는 메서드 (임계 구역)
private static void increment() {
for (int i = 0; i < 10000; i++) {
lock.lock(); // 뮤텍스 획득
try {
counter++; // 임계 구역 – 공유 자원 수정
} finally {
lock.unlock(); // 반드시 해제해야 데드락 방지
}
}
}
}
요약 설명
- ReentrantLock은 Java에서 뮤텍스로 자주 사용하는 클래스이다.
- lock()을 호출한 스레드만 임계 구역에 진입할 수 있으며, 작업 후 반드시 unlock() 해야 한다.
- 위 코드에서 두 스레드가 동시에 counter를 증가시켜도 정확하게 20000이 출력된다.

장단점
장점
- 구현이 단순하고 직관적이다.
- 상호 배제 보장이 확실하다.
단점
- 데드락(Deadlock)의 위험이 존재한다.
- 우선순위 역전(Priority Inversion) 문제가 발생할 수 있다.
세마포어(Semaphore)

세마포어는 정수 값을 가지는 동기화 객체로, 동시에 접근할 수 있는 프로세스 또는 스레드의 수를 제어한다. 주로 카운팅 세마포어(Counting Semaphore)와 이진 세마포어(Binary Semaphore)로 구분된다.
구성 요소
- 정수 값(S): 초기값으로 접근 가능한 자원의 수를 나타냄
- 두 가지 기본 연산:
- wait() 또는 P() 또는 down()
→ 세마포어 값을 1 감소시킴. 값이 0보다 작아지면 블로킹 - signal() 또는 V() 또는 up()
→ 세마포어 값을 1 증가시킴. 대기 중인 프로세스가 있으면 깨움
- wait() 또는 P() 또는 down()
세마포어(Semaphore) – Semaphore 사용
import java.util.concurrent.Semaphore;
public class SemaphoreExample {
// 동시에 접근 가능한 최대 스레드 수: 3
private static final Semaphore semaphore = new Semaphore(3);
public static void main(String[] args) {
// 10개의 작업 스레드 생성
for (int i = 1; i <= 10; i++) {
int threadNum = i;
new Thread(() -> accessResource(threadNum)).start();
}
}
private static void accessResource(int threadNum) {
try {
// 세마포어 획득 시도 (자원이 없으면 대기)
semaphore.acquire();
System.out.println("Thread " + threadNum + " → 자원 접근 중");
// 자원 처리 시뮬레이션 (2초)
Thread.sleep(2000);
System.out.println("Thread " + threadNum + " → 자원 반환");
} catch (InterruptedException e) {
e.printStackTrace();
} finally {
// 세마포어 해제 (자원 반환)
semaphore.release();
}
}
}
요약 설명
- Semaphore(3) → 동시에 3개 스레드만 접근할 수 있도록 제한
- acquire() → 자원을 획득 (없으면 대기)
- release() → 자원을 반환 (다음 스레드에 기회 제공)
- 이 코드를 실행하면, 10개의 스레드 중 3개만 동시에 실행되며, 나머지는 대기 후 순차적으로 자원을 사용한다.

세마포어의 종류
- 카운팅 세마포어 (Counting Semaphore)
- 값이 0보다 크거나 같은 정수를 가짐
- 동시 접근 가능한 자원 수를 제어
- 예: 프린터 3대 → 세마포어 초기값을 3으로 설정
- 이진 세마포어 (Binary Semaphore)
- 0 또는 1의 값만 가짐
- 뮤텍스처럼 동작하지만 소유권이 없음
- 일반적으로 프로세스 간 상호 배제에 사용
특징
- 소유권 없음: 세마포어는 소유 개념이 없으므로, wait()를 호출한 프로세스가 아닌 프로세스가 signal()을 호출해도 문제가 되지 않는다.
- 프로세스 간 동기화 가능: 세마포어는 프로세스 간 IPC(Inter-Process Communication) 방식으로도 사용 가능하다.
- 더 일반화된 개념: 뮤텍스보다 유연한 동기화 제어가 가능하다.
뮤텍스와 세마포어의 차이
항목 뮤텍스 (Mutex) 세마포어 (Semaphore)
상태 | Binary (0 or 1) | Counting (≥ 0) |
소유권 | 있음 | 없음 |
사용 범위 | 스레드 간 동기화 | 프로세스/스레드 간 동기화 |
해제 가능 여부 | 락을 획득한 스레드만 해제 가능 | 어떤 스레드든 signal 가능 |
사용 목적 | 상호 배제 | 상호 배제 및 동기화 |
데드락 가능성 | 있음 | 있음 |
정리
- 임계 구역은 공유 자원을 사용하는 코드 영역이며, 경쟁 상태를 피하기 위해 보호해야 한다.
- 상호 배제는 임계 구역의 동시 접근을 막는 기법이다.
- 뮤텍스는 소유권이 있는 락을 통해 하나의 스레드만 임계 구역에 접근하게 한다.
- 세마포어는 정수 기반의 동기화 도구로, 자원 접근 수를 제어하거나, 프로세스 간 통신 및 순서를 조절하는 데도 사용된다.
- 뮤텍스는 주로 스레드 동기화, 세마포어는 프로세스/스레드 모두에 쓰이며 더 일반화된 개념이다.
참고하면 좋은 영상
https://www.youtube.com/watch?v=NL9JQh5bbZ8
질문이 들어온다면?
1. "뮤텍스와 세마포어의 차이를 설명해주세요."
뮤텍스는 하나의 스레드만 임계 구역에 접근할 수 있도록 하는 동기화 객체이며, 소유권 개념이 있어 락을 획득한 스레드만 해제할 수 있습니다. 반면 세마포어는 여러 스레드가 접근할 수 있도록 허용하며, 주로 리소스의 수를 관리하는 데 사용됩니다. 뮤텍스는 binary(0 또는 1) 개념인 반면, 세마포어는 counting 방식으로 동작합니다. 또한 세마포어는 소유권 개념이 없기 때문에 다른 스레드가 해제하는 것도 가능합니다. 요약하자면, 뮤텍스는 상호배제를, 세마포어는 리소스 제어와 동기화를 위한 도구입니다.
2. "뮤텍스를 사용하는 예시를 들어주세요."
뮤텍스는 다중 스레드 환경에서 공유 자원에 대한 동시 접근을 방지할 때 사용됩니다. 예를 들어, 여러 스레드가 동시에 로그 파일을 쓰는 상황에서 뮤텍스를 이용해 한 번에 하나의 스레드만 접근하도록 제한할 수 있습니다. 이를 통해 Race Condition을 방지하고, 데이터 일관성을 보장할 수 있습니다. Java에서는 ReentrantLock, C++에서는 std::mutex 같은 클래스로 구현할 수 있습니다.
3. "세마포어는 어떤 상황에서 더 적합한가요?"
세마포어는 제한된 개수의 리소스를 여러 스레드가 공유해야 할 때 적합합니다. 예를 들어, 데이터베이스 연결 풀처럼 동시에 최대 10개의 연결만 허용해야 하는 경우, 세마포어의 초기값을 10으로 설정해 접근을 제어할 수 있습니다. 또한 생산자-소비자 문제처럼 순서를 보장하며 동기화가 필요한 상황에서도 유용합니다. 뮤텍스는 단일 자원 보호에 초점이 맞춰져 있지만, 세마포어는 그보다 유연하게 리소스 수를 관리할 수 있습니다.
4. "뮤텍스를 잘못 사용하면 발생할 수 있는 문제는 무엇인가요?"
뮤텍스를 잘못 사용하면 데드락이 발생할 수 있습니다. 예를 들어, 두 스레드가 서로가 가진 락을 기다리는 상황이 되면 프로그램이 영원히 멈춥니다. 또한, 락을 획득한 스레드가 예외로 인해 unlock을 수행하지 않으면 다른 스레드가 영원히 대기하게 됩니다. 이러한 문제는 락 해제를 finally 블록에 넣거나 try-with-resources 패턴을 사용하는 것으로 예방할 수 있습니다.
5. "세마포어를 잘못 구현했을 때 발생할 수 있는 대표적인 동시성 문제는요?"
세마포어를 잘못 구현하면 자원 고갈(Starvation), 데드락, 우선순위 역전(Priority Inversion) 같은 문제가 발생할 수 있습니다. 예를 들어, wait() 호출만 반복하고 signal()을 누락하면 리소스가 반환되지 않아 모든 스레드가 블로킹될 수 있습니다. 또한 signal 순서가 잘못되면 의도한 동기화 흐름이 깨져 예기치 않은 동작을 초래합니다. 정확한 초기값 설정과 signal/wait 짝을 맞추는 것이 매우 중요합니다.
'Computer Science > OperatingSystem' 카테고리의 다른 글
[OS] DeadLock(교착상태) (0) | 2025.03.13 |
---|---|
[OS] 운영체제란? (0) | 2025.03.06 |
[OS] 컨텍스트 스위칭이란?(Context Swiching) (CS스터디) (0) | 2023.07.07 |
[OS] 프로세스와 스레드는 어떤 차이점이 있나요? (0) | 2023.06.30 |
[OS] 요구 페이징 (0) | 2023.04.19 |