Arc와 Mutex 사용 시기: Rust의 동시성 프로그래밍
카테고리
프로그래밍/소프트웨어 개발
서브카테고리
개발 툴
대상자
Rust로 동시성 또는 멀티스레드 프로그램을 구현하는 개발자
- 난이도: 중급 (소유권 시스템과 스레드 안전성 이해 필요)*
핵심 요약
- Arc(
Atomic Reference Count
)는 스레드 간 공유 소유권을 위한 스마트 포인터 - Mutex(
Mutual Exclusion
)는 스레드 간 데이터 변경 시 동기화를 위한 락 기반 구현 - Arc + Mutex 조합은 공유 가능한 가변 데이터에 필수적 (예: 멀티스레드 카운터)
- 피해야 할 함정: 데드락, 락 경쟁, poisoned lock 대응
섹션별 세부 요약
1. Rust의 동시성 모델
- Rust는 컴파일 시점에 데이터 레이스 제거를 통해 안전한 동시성 프로그래밍 지원
- 소유권 시스템이 복수의 가변 참조를 허용하지 않음 (스레드 간 데이터 공유 시 문제 발생)
2. Arc와 Mutex의 역할
- Arc
Arc::clone()
을 통해 스레드 간 데이터 공유 가능- 레퍼런스 카운트가 원자적으로 증감하여 메모리 누수 방지
- Mutex
lock()
메서드로 데이터 변경 시 락 획득- 독점적 접근 보장 (스레드 간 데이터 오염 방지)
3. Arc + Mutex 사용 시기
- 공유 가능한 가변 데이터가 필요할 때 (예: 멀티스레드 카운터)
Arc
로 스레드 간 데이터 공유,Mutex
로 동시 수정 방지- 예제 코드:
```rust
let counter = Arc::new(Mutex::new(0)); // Arc로 공유, Mutex로 락 적용
let counter_clone = Arc::clone(&counter);
let handle = thread::spawn(move || {
let mut num = counter_clone.lock().unwrap(); // 락 획득
- num += 1; // 안전한 데이터 변경
});
```
4. 데드락 및 성능 문제
- 데드락 발생 조건:
- 두 스레드가 서로 다른 순서로 락을 획득 (예:
data1.lock()
후data2.lock()
vsdata2.lock()
후data1.lock()
) - 해결 방법: 락 획득 순서 통일
- 성능 저하 원인:
- 락 경쟁이 심할 경우 스레드 대기 시간 증가
- 해결 방법: critical section 범위 최소화 (예:
lock()
후 즉시unlock()
)
5. Poisoned Lock과 예외 처리
- Poisoned Lock: 락 획득 시 스레드가 panic 발생으로 인해 락 상태가 손상됨
- 대응 방법:
```rust
let mut num = counter.lock().unwrap_or_else(|err| {
println!("Mutex lock poisoned: {:?}", err);
err.into_inner()
});
```
결론
- Arc + Mutex은 멀티스레드 환경에서 공유 가능한 가변 데이터에 필수적
- 데드락 방지를 위해 락 획득 순서 통일하고, critical section 범위 최소화
- poisoned lock은
Result
를 통해 안전하게 처리 - 추가적으로
RwLock
또는Atomic
타입을 활용한 비동기 동시성 구현도 고려할 것