race condition 이 발생하는 이유 : 병렬적(동시에)으로 실행된다.
→ 부분부분마다 각자 실행해서 해결한다.
Semaphores
: semaphore 값은 사용 가능한 리소스의 개수를 타타낸다.
- P 연산: 세마포어 값을 감소시킨다.
- 값이 0보다 작아지면 : block - lock
- 리소스를 사용
- V 연산: 세마포어 값을 증가시킨다.
- 값이 0보다 커지면 : 블록된 스레드 중 하나를 깨워 실행을 재개시킵니다. 즉, V 연산은 리소스를 반납하겠다는 의미입니다.
- unlock
Semaphore를 Mutex처럼 사용하기
- 세마포어를 초기값 1로 설정하면 뮤텍스처럼 사용할 수 있습니다.
Condition Variables
- 특정 조건이 만족될 때까지 스레드(논리 흐름)를 대기시키는 동기화 도구입니다.
- 뮤텍스와 함께 사용되어 효율적인 blocking을 제공합니다.
- 뮤텍스를 잠근 스레드는 조건 변수에서 대기하여 조건이 충족될 때까지 블록될 수 있습니다.
- 반복문에서 대기
- awakened 일때 condition 확인
- condition을 만족하면 반복문을 빠져나옴
- 조건을 만족시킬 수 있는 다른 스레드는 대기 중인 스레드에게 신호를 보내 깨울 수 있습니다.
Condition Variables flow
- 뮤텍스 획득: 조건 변수를 사용하기 전에 관련된 공유 자원을 보호하는 뮤텍스를 먼저 획득해야 합니다.
- 조건 대기 (Wait): 특정 조건이 만족될 때까지 스레드는 조건 변수에서 대기합니다. 대기하는 동안 스레드는 자동으로 뮤텍스를 해제하여 다른 스레드가 공유 자원에 접근할 수 있도록 합니다.
- 조건 만족 알림 (Signal/Broadcast): 다른 스레드가 조건을 만족시키면, 조건 변수에 대기 중인 스레드에게 알림을 보냅니다. 알림은 두 가지 방식으로 보낼 수 있습니다.
- Signal: 대기 중인 스레드 중 하나를 깨웁니다.
- Broadcast: 대기 중인 모든 스레드를 깨웁니다.
- 조건 재확인: 깨어난 스레드는 다시 뮤텍스를 획득하고, 조건이 실제로 만족되었는지 확인합니다. 만약 조건이 만족되지 않았다면 다시 대기 상태로 돌아가고, 만족되었다면 임계 영역에 진입하여 작업을 수행합니다.
mutex m;
condition_variable cv;
int d = 0; // 공유 데이터
void signaler() {
lock(m);
d++; // 공유 데이터 수정
cv.notify_one(); // 대기 중인 스레드에게 알림
unlock(m);
}
void waiter() {
lock(m);
while (d == 0) { // 특정 조건(d == 0)이 만족될 때까지 대기
cv.wait(lock);
}
// 조건이 만족되었을 때 실행할 동작
std::cout << "Condition met. Data: " << d;
unlock(m);
}
int main() {
std::thread t1(waiter);
std::thread t2(signaler);
t1.join();
t2.join();
return 0;
}
Mutex 와의 상호작용