Send 与 Sync 特征
- 实现
Send的类型可以在线程间安全的传递其所有权 - 实现
Sync的类型可以在线程间安全的共享(通过引用) - 若类型
T的引用&T是Send,则T是Sync。因为共享的前提是要能发送。
将Rc传递到子线程中
use std::rc::Rc; use std::thread; fn main() { let demo = Rc::new(0); thread::spawn(move || { // ^^^^ `Rc<i32>` cannot be sent between threads safely println!("{}", *demo); }); }
是因为Rc没有实现Send和Sync这两个trait
模拟实现不能移入子线程的数据
手动实现 Send 和 Sync 是不安全的。
#![feature(negative_impls)] use std::{marker, thread}; fn main() { #[derive(Debug)] struct Demo (); impl Demo { fn new() -> Demo { Demo () } } // 强调 Demo 不实现Sync 与 Send impl !marker::Sync for Demo {} impl !marker::Send for Demo {} let demo: Demo = Demo::new(); // 下面这行会编译失败,因为 Demo 不是 Send thread::spawn(move || { // ^^^^ 这里将会报错 Dome不能在线程之间安全发送 println!("move to: {:?}", demo); }); }
若复合类型的所有成员都是Send或Sync,那么该复合类型自动拥有Send或Sync。(自动派生)
同理。只要复合类型中有一个成员不是Send或Sync,那么该复合类型也就不是Send或Sync。
裸指针也不能在线程间传递共享
use std::thread; fn main() { let mut num = 5u8; let mum_p = &mut num as *mut u8; println!("mum_p: {:p}", mum_p); unsafe { println!("mut: {}", *mum_p); } // 将裸指针移入子线程 thread::spawn(move || { // ^^^^ `*mut u8` cannot be sent between threads safely unsafe { println!("mut: {}", *mum_p); } }).join().unwrap(); }
使用Newtype 模式实现将裸指针传入子线程
use std::thread; fn main() { let num = 5u8; let num_p = &num as *const u8; println!("num p = {:p}", num_p); unsafe { println!("num {}", *num_p); } // 使用newtype #[derive(Debug)] struct Wrapper(*const u8); impl Wrapper { fn value(&self) -> *const u8 { self.0 } } // 为 Wrapper 实现 Send 与 Sync trait unsafe impl Sync for Wrapper {} unsafe impl Send for Wrapper {} // 如果注释上面两行代码将会报错 let wrapper = Wrapper(num_p); thread::spawn(move || { let result = wrapper.value(); unsafe { println!("in thread: {:p} = {}", result, *result); } }).join().unwrap(); }