消息传递
实例
use std::sync::mpsc;
use std::thread;
// 使用通道在多个线程中传递消息
fn main() {
let (tx, rx) = mpsc::channel();
thread::spawn(move || {
// send 函数会获取其参数的所有权
// 并移动这个值归接收者所有
let v = vec![7, 8, 9];
for i in v {
tx.send(i).unwrap();
}
});
let recver = thread::spawn(move || {
// 使用迭代方式从通道中取值
for i in rx {
println!("{}", i);
}
});
recver.join().unwrap();
}
共享状态
使用互斥器(Mutex
)来保护数据,每次访问数据需要获取所锁:Mutex<T>
是一个智能指针lock()
调用 返回 一个叫做 MutexGuard
的智能指针, 这个智能指针实现了Deref
来指向其内部数据;其也提供了一个Drop
实现当MutexGuard
离开作用域时自动释放锁
结合Arc
它是一个原子引用计数(atomically reference counted)类型
适用于多线程场景
和Rc<T>
对比:
Arc<T>
对应Rc<T>
,提供引用计数功能Mutex<T>
对应RefCell<T>
,提供内部可变性功能
实例
use std::{
sync::{Arc, Mutex},
thread::{self, JoinHandle},
};
// 使用mutex在多线程中共享数据
fn main() {
// 创建具有多所有权的互斥器
let m = Arc::new(Mutex::new(0));
// 存放线程的handle
let mut handles: Vec<JoinHandle<()>> = Vec::new();
for _ in 0..10 {
let counter = m.clone();
// 在单独的线程中对互斥器进行修改
let handle = thread::spawn(move || {
// 调用 lock 后返回的是 MutexGuard 类型的智能指针
// 来访问内部数据
// 类似于 RefCell, 提供了内部可变性
let mut num = counter.lock().unwrap();
*num += 1;
});
handles.push(handle);
}
for handle in handles {
handle.join().unwrap();
}
println!("{:?}", *m.lock().unwrap());
}
Send,Sync trait
Send
Send
标记trait
表明类型的所有权可以在线程间传递。
几乎所有的Rust
类型都是Send
的,但是Rc<T>
是不能Send
的,这两个线程都可能同时更新引用计数。
任何完全由Send
的类型组成的类型也会自动被标记为Send
。
几乎所有基本类型都是Send
的,除了裸指针(raw pointer
)。
Sync
Sync
标记trait
表明一个实现了Sync
的类型可以安全的在多个线程中拥有其值的引用。
如果&T
(T
的引用)是Send
的话T
就是Sync
的,这意味着其引用就可以安全的发送到另一个线程
基本类型是Sync
的,完全由Sync
的类型组成的类型也是Sync
的。
实例
直接往std::thread::spawn()
里面传引用会报错:borrowed value does not live long enough
这里使用crossbeam
库,不过需要多套一层thread::scope
:
use crossbeam::thread;
fn main() {
let mut greeting = String::from("Hello");
let greeting_ref = &greeting;
thread::scope(|scoped_thread| {
// spawn 3 threads
for n in 1..=3 {
// greeting_ref copied into every thread
scoped_thread.spawn(move |_| {
println!("{} {}", greeting_ref, n); // prints "Hello {n}"
});
}
// line below could cause UB or data races but compiler rejects it
// greeting += " world"; // ❌ cannot mutate greeting while immutable refs exist
});
// can mutate greeting after every thread has joined
greeting += " world"; // ✅
println!("{}", greeting); // prints "Hello world"
}