멀티스레딩 또는 멀티프로세싱 환경에서 둘 이상의 실행 흐름이 동시에 같은 자원에 접근하고, 그 접근 순서에 따라 결과가 달라지는 현상을 Race Condition(경쟁 상태) 이라고 한다.
동기화가 제대로 이루어지지 않은 상태에서 발생하며, 심각한 버그나 예측 불가능한 동작을 초래할 수 있다.

여러 스레드가 자원에 먼저 접근하려고 "경쟁" 하기 때문이다.
이 경쟁에서 누가 먼저 도착하느냐에 따라 결과가 달라진다면, Race Condition이 발생한 것이다.
예를 들어, 두 스레드가 동시에 하나의 전역 변수를 수정한다면 다음과 같은 문제가 발생할 수 있다.
// 공유 변수
int count = 0;
// 스레드 A
count++; // 1 증가
// 스레드 B
count++; // 1 증가
이론적으로 count = 2가 되어야 하지만, 두 스레드가 메모리에 접근하고 값을 증가시키는 시점이 겹치면 결과는 1이 될 수도 있다.
두 스레드가 동시에 같은 계좌에서 출금을 시도한다고 가정해보자.
if (balance >= amount) {
balance -= amount;
}
balance를 읽고 충분한 금액이 있다고 판단즉, 데이터가 변경되기 전과 후 사이에 다른 스레드가 개입하면 예기치 못한 동작이 일어난다.
Race Condition을 예방하기 위해선 스레드 간 동기화가 반드시 필요하다.
| 도구 | 설명 |
|---|---|
Mutex | 하나의 스레드만 임계 구역에 진입 허용 |
Semaphore | 제한된 수의 접근만 허용 |
Spin Lock | 반복 검사하며 락 대기 |
Condition Variable | 조건이 충족될 때까지 대기 |
Atomic 변수 | 원자적(Atomic) 연산으로 Race Condition 자체 방지 |
대부분의 경우, Mutex 또는 Semaphore를 이용한 임계 구역 보호(Critical Section Protection) 으로 문제를 해결한다.
#include <pthread.h>
#include <stdio.h>
int counter = 0;
void* increment(void* arg) {
for (int i = 0; i < 1000000; i++) {
counter++; // 동기화 없음!
}
return NULL;
}
int main() {
pthread_t t1, t2;
pthread_create(&t1, NULL, increment, NULL);
pthread_create(&t2, NULL, increment, NULL);
pthread_join(t1, NULL);
pthread_join(t2, NULL);
printf("Final Counter: %d\n", counter); // 예상보다 작을 수 있음
}
counter가 2000000이 되지 않고 그보다 작게 나오는 이유는Race Condition때문이다.