消息传递
实例
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));// 存放线程的handlelet 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 threadsfor n in 1..=3 {// greeting_ref copied into every threadscoped_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 joinedgreeting += " world"; // ✅println!("{}", greeting); // prints "Hello world"}
