1. threading.Condition이란?
threading.Condition은 Python의 스레드 동기화를 지원하는 객체로, 특정 조건이 충족될 때까지 스레드가 대기하거나, 다른 스레드가 조건을 알리는 데 사용됩니다. 이를 통해 여러 스레드 간에 작업을 효율적으로 조율할 수 있습니다.
Condition 객체는 내부적으로 Lock이나 RLock과 같은 락을 사용하여 상태를 보호하며, 스레드 간의 안전한 데이터 교환을 돕습니다.
2. 주요 메서드
Condition 객체에서 제공하는 메서드들은 스레드 간 통신과 조건 동작을 수행하는 데 필수적입니다.
(1) wait()
- 호출한 스레드가 notify()나 notify_all() 호출로 신호를 받을 때까지 대기합니다.
- with 블록 내에서 호출해야 하며, 호출 시 락을 자동으로 해제합니다. 신호를 받으면 락을 다시 획득합니다.
(2) notify()
- 대기 중인 스레드 중 하나에게 신호를 보내 대기 상태를 해제합니다.
- 역시 with 블록 내에서 호출해야 합니다.
(3) notify_all()
- 대기 중인 모든 스레드에게 신호를 보내 대기를 해제합니다.
(4) acquire() / release()
- 내부 락을 명시적으로 제어할 때 사용합니다. 하지만 일반적으로 with 문을 사용하는 것이 권장됩니다.
3. 기본 사용 예제
import threading
# 공유 리소스와 Condition 객체
shared_data = []
condition = threading.Condition()
# 생산자 스레드
def producer():
with condition:
print("생산자가 데이터 추가 중...")
shared_data.append(1)
print("데이터 추가 완료. 소비자에게 신호 보냄.")
condition.notify()
# 소비자 스레드
def consumer():
with condition:
print("소비자가 데이터 대기 중...")
condition.wait()
print("데이터 수신: ", shared_data.pop())
# 스레드 생성
producer_thread = threading.Thread(target=producer)
consumer_thread = threading.Thread(target=consumer)
# 스레드 시작
consumer_thread.start()
producer_thread.start()
# 스레드 종료 대기
producer_thread.join()
consumer_thread.join()
4. 실행 결과
위 코드를 실행하면 소비자 스레드가 wait() 상태로 대기하다가, 생산자가 notify()를 호출한 뒤 데이터를 처리하는 과정을 볼 수 있습니다.
소비자가 데이터 대기 중...
생산자가 데이터 추가 중...
데이터 추가 완료. 소비자에게 신호 보냄.
데이터 수신: 1
5. 주요 활용 사례
threading.Condition은 다음과 같은 상황에서 유용합니다:
- 생산자-소비자 패턴: 데이터를 생성하는 생산자와 이를 소비하는 소비자 간의 작업 조율.
- 스레드 간 협력 작업: 특정 조건이 충족될 때까지 스레드가 대기하거나 신호를 통해 진행 상태를 알림.
- 멀티스레드 환경에서의 데이터 처리: 복수의 스레드가 데이터를 동시에 처리하지 못하도록 제어.
6. 주의 사항
- 락 보호: Condition 객체의 메서드 (wait, notify, notify_all)는 반드시 with condition 블록 내에서 호출해야 합니다. 그렇지 않으면 RuntimeError가 발생합니다.
- 교착 상태 방지: 여러 스레드가 동시에 wait() 상태에 있을 경우, 올바르게 신호를 보내기 위한 설계가 중요합니다.
- 효율적인 사용: 과도한 대기 및 신호 사용은 성능 저하를 초래할 수 있으므로 필요 최소한으로 사용해야 합니다.
threading.Condition은 멀티스레드 프로그래밍에서 강력한 도구로, 복잡한 동기화 문제를 해결하는 데 유용합니다. 올바르게 활용하면 안전하고 효율적인 스레드 작업 흐름을 구현할 수 있습니다.