Mutex는 보통 스마트 포인터가 보유하는 컨테이너 데이터 구조로서, 데이터를 가져오거나 안에 있는 것에 대한 변경 가능한 또는 불가능한 참조를 할 수 있게 해준다.
잠긴 참조를 통해 OS가 동시에 오직 하나의 CUP만 데이터에 접근 가능하도록 하고, 원래 스레드가 끝날 때까지 다른 스레드들을 막음으로써 참조 남용을 방지한다.
Mutex는 여러 개의 CPU 스레드가 같은 데이터에 접근하는 걸 조율하는 방법
use std::sync::Mutex;
struct Pie {
value: i32,
}
impl Pie {
fn up(&mut self) {
self.value += 1;
}
}
fn main() {
let heap_pie = Mutex::new(Pie{value: 0});
let ref_pie = heap_pie.lock().unwrap();
println!("val : {}", ref_pie.value);
}
스레드 안정성을 가진 참조 카운트 증가 방식을 사용한다는 걸 제외하고는 Rc와 동일
동일한 Mutex에 다수의 참조를 가질 때 종종 사용
Rc<Vec<Foo>>
Rc<RefCell<Foo>>
Arc<Mutex<Foo>>
use std::cell::RefCell;
use std::rc::Rc;
struct Pie {
value: i32,
}
impl Pie {
fn up(&mut self) {
self.value += 1;
}
}
struct Basket {
// Rc : 여러 스마트 포인터 접근 가능
// RefCekk : 참조이기에 항상 유효한 메모리
pie: Rc<RefCell<Pie>>
}
impl Basket {
fn add(&self) {
let mut p = self.pie.borrow_mut();
p.up();
}
}
fn main() {
// 컨테이너와 다른 생명 주기를 가지기 위해 참조(Ref) 대신 얕은 복사
let pie = Rc::new(RefCell::new(Pie {value: 0}));
let ferris = Basket {
pie: pie.clone(),//Rc
};
let sarah = Basket {
pie: pie.clone(),//Rc
};
ferris.add();
sarah.add();
let p = pie.borrow();//RefCell, `.` 사용시 역참조는 컴파일러가 알아서 추가
println!("{}", p.value);
}
이런 조합이 많이 포함된 주제가 있다.
내부 데이터를 변경하기 위해 immutable한 데이터 유형(복수의 smart pointer가 소유할 수 있음)을 사용한다.
이를 Rust에서는 내부 가변성 패턴이라고 한다.
이는 Rust의 컴파일 타임 체크와 동일 수준의 안전성으로 런타임의 메모리 사용 규칙을 변경할 수 있는 패턴이다.