Today we will introduce (Rc
, RefCell
) and( Arc
, Mutex
) In advanced Rust programming.
Rc<T>
only for use in single-threaded scenarios.
Rc<T> is a reference counter.
T is read-only
RefCell<T>
only for use in single-threaded scenarios.
Interior mutability is a design pattern in Rust that allows you to mutate data even when there are immutable references to that data;
Rc<RefCell<T»
only for use in single-threaded scenarios.
#[derive(Debug)]
enum List {
Cons(Rc<RefCell<i32>>, Rc<List>),
Nil,
}
use crate::List::{Cons, Nil};
use std::cell::RefCell;
use std::rc::Rc;
fn main() {
let value = Rc::new(RefCell::new(5));
let a = Rc::new(Cons(Rc::clone(&value), Rc::new(Nil)));
let b = Cons(Rc::new(RefCell::new(3)), Rc::clone(&a));
let c = Cons(Rc::new(RefCell::new(4)), Rc::clone(&a));
*value.borrow_mut() += 10;
println!("a after = {:?}", a);
println!("b after = {:?}", b);
println!("c after = {:?}", c);
}
Arc<T>
Fortunately, Arc<T>
is a type like Rc<T>
that is safe to use in concurrent situations.
Arc<T>’s counter is atomic, So we can use it in concurrency.
Mutex<T>
lock the variable access permission. thread-safe.
Arc<Mutex<T»
use std::sync::{Arc, Mutex};
use std::thread;
fn main() {
let counter = Arc::new(Mutex::new(0));
let mut handles = vec![];
for _ in 0..10 {
let counter = Arc::clone(&counter);
let handle = thread::spawn(move || {
let mut num = counter.lock().unwrap();
*num += 1;
});
handles.push(handle);
}
for handle in handles {
handle.join().unwrap();
}
println!("Result: {}", *counter.lock().unwrap());
}
don’t forget implement trait Send
and Sync
for T
struct X{
}
unsafe impl Sync for X{
}
unsafe impl Send for X{
}
Arc::new(Mutex::new(X::new()));