Send 和 Sync 是 Rust 并发安全的基石,但名字容易混。这篇不背定义,而是对 22 个常见类型逐个编译验证,再看 Rc、RefCell、裸指针在线程里到底怎么报错,以及为什么一个字段能拖垮整个结构体。
类型 Send Sync i32 ✓ ✓ String ✓ ✓ Vec<u8> ✓ ✓ &str ✓ ✓ &mut i32 ✓ ✓ Rc<i32> ✗ ✗ Arc<i32> ✓ ✓ Cell<i32> ✓ ✗ RefCell<i32> ✓ ✗ Mutex<i32> ✓ ✓ RwLock<i32> ✓ ✓ AtomicUsize ✓ ✓ Mutex<Rc<i32>> ✗ ✗ Arc<RefCell<i32>> ✗ ✗ Arc<Mutex<i32>> ✓ ✓ *const i32 ✗ ✗ MutexGuard<i32> ✗ ✓ mpsc::Sender<i32> ✓ ✓ mpsc::Receiver<i32> ✓ ✗ Box<dyn Fn()> ✗ ✗ Box<dyn Fn() + Send> ✓ ✗ Weak<i32>(Rc) ✗ ✗
Rc 与 Arc 的区别见Arc<T> 与跨线程共享所有权。
源码:
1 | use std::rc::Rc; use std::thread;
2 | fn main() { let r = Rc::new(5); let h = thread::spawn(move || { println!("{}", r); }); h.join().unwrap(); }
编译:失败
error[E0277]: `Rc<i32>` cannot be sent between threads safely
--> <实验目录>/src/u86a.rs:2:55
|
2 | fn main() { let r = Rc::new(5); let h = thread::spawn(move || { println!("{}", r); }); h.join().unwrap(); }
| ------------- -------^^^^^^^^^^^^^^^^^^^^^^^
| | |
| | `Rc<i32>` cannot be sent between threads safely
| | within this `{closure@u86a.rs:2:55}`
| required by a bound introduced by this call
|
= help: within `{closure@u86a.rs:2:55}`, the trait `Send` is not implemented for `Rc<i32>`
note: required because it's used within this closure
--> <实验目录>/src/u86a.rs:2:55
|
2 | fn main() { let r = Rc::new(5); let h = thread::spawn(move || { println!("{}", r); }); h.join().unwrap(); }
| ^^^^^^^
note: required by a bound in `spawn`
--> <rust 标准库源码>/library/std/src/thread/functions.rs:128:8
|
125 | pub fn spawn<F, T>(f: F) -> JoinHandle<T>
| ----- required by a bound in this function
...
128 | F: Send + 'static,
| ^^^^ required by this bound in `spawn`
= note: the full name for the type has been written to '<实验目录>/bin/u86a.long-type-3231345782421694739.txt'
= note: consider using `--verbose` to print the full type name to the console
error: aborting due to 1 previous error
For more information about this error, try `rustc --explain E0277`. 源码:
1 | use std::cell::RefCell; use std::thread;
2 | fn main() { let c = RefCell::new(1); thread::scope(|s| { s.spawn(|| { *c.borrow_mut() += 1; }); }); println!("{:?}", c); }
编译:失败
error[E0277]: `RefCell<i32>` cannot be shared between threads safely
--> <实验目录>/src/u86b.rs:2:66
|
2 | fn main() { let c = RefCell::new(1); thread::scope(|s| { s.spawn(|| { *c.borrow_mut() += 1; }); }); println!("{:?}", c); }
| ----- ^^^^^^^^^^^^^^^^^^^^^^^^^^^^ `RefCell<i32>` cannot be shared between threads safely
| |
| required by a bound introduced by this call
|
= help: the trait `Sync` is not implemented for `RefCell<i32>`
= note: if you want to do aliasing and mutation between multiple threads, use `std::sync::RwLock` instead
= note: required for `&RefCell<i32>` to implement `Send`
note: required because it's used within this closure
--> <实验目录>/src/u86b.rs:2:66
|
2 | fn main() { let c = RefCell::new(1); thread::scope(|s| { s.spawn(|| { *c.borrow_mut() += 1; }); }); println!("{:?}", c); }
| ^^
note: required by a bound in `Scope::<'scope, 'env>::spawn`
--> <rust 标准库源码>/library/std/src/thread/scoped.rs:203:28
|
201 | pub fn spawn<F, T>(&'scope self, f: F) -> ScopedJoinHandle<'scope, T>
| ----- required by a bound in this associated function
202 | where
203 | F: FnOnce() -> T + Send + 'scope,
| ^^^^ required by this bound in `Scope::<'scope, 'env>::spawn`
error: aborting due to 1 previous error
For more information about this error, try `rustc --explain E0277`.
编译:成功
运行(退出码 0):
5Mutex 见Mutex<T> 与内部可变性。
源码:
1 | use std::thread;
2 | struct P(*mut i32);
3 | fn main() { let mut x = 1; let p = P(&mut x); thread::spawn(move || { let q = p; println!("{:p}", q.0); }).join().unwrap(); }
编译:失败
error[E0277]: `*mut i32` cannot be sent between threads safely
--> <实验目录>/src/u86d.rs:3:61
|
3 | fn main() { let mut x = 1; let p = P(&mut x); thread::spawn(move || { let q = p; println!("{:p}", q.0); }).join().unwrap(); }
| ------------- -------^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
| | |
| | `*mut i32` cannot be sent between threads safely
| | within this `{closure@u86d.rs:3:61}`
| required by a bound introduced by this call
|
= help: within `{closure@u86d.rs:3:61}`, the trait `Send` is not implemented for `*mut i32`
note: required because it appears within the type `P`
--> <实验目录>/src/u86d.rs:2:8
|
2 | struct P(*mut i32);
| ^
note: required because it's used within this closure
--> <实验目录>/src/u86d.rs:3:61
|
3 | fn main() { let mut x = 1; let p = P(&mut x); thread::spawn(move || { let q = p; println!("{:p}", q.0); }).join().unwrap(); }
| ^^^^^^^
note: required by a bound in `spawn`
--> <rust 标准库源码>/library/std/src/thread/functions.rs:128:8
|
125 | pub fn spawn<F, T>(f: F) -> JoinHandle<T>
| ----- required by a bound in this function
...
128 | F: Send + 'static,
| ^^^^ required by this bound in `spawn`
= note: the full name for the type has been written to '<实验目录>/bin/u86d.long-type-12970848410698637505.txt'
= note: consider using `--verbose` to print the full type name to the console
error: aborting due to 1 previous error
For more information about this error, try `rustc --explain E0277`.
编译:成功
运行(退出码 0):
子线程通过 unsafe impl Send 的指针得到 42unsafe 的边界见unsafe 的安全边界。
源码:
1 | use std::rc::Rc;
2 | struct Ok1 { a: i32, b: String }
3 | struct Bad1 { a: i32, b: Rc<i32> }
4 | fn assert_send<T: Send>() {}
5 | fn main() { assert_send::<Ok1>(); assert_send::<Bad1>(); }
编译:失败
error[E0277]: `Rc<i32>` cannot be sent between threads safely
--> <实验目录>/src/u86f.rs:5:49
|
5 | fn main() { assert_send::<Ok1>(); assert_send::<Bad1>(); }
| ^^^^ `Rc<i32>` cannot be sent between threads safely
|
= help: within `Bad1`, the trait `Send` is not implemented for `Rc<i32>`
note: required because it appears within the type `Bad1`
--> <实验目录>/src/u86f.rs:3:8
|
3 | struct Bad1 { a: i32, b: Rc<i32> }
| ^^^^
note: required by a bound in `assert_send`
--> <实验目录>/src/u86f.rs:4:19
|
4 | fn assert_send<T: Send>() {}
| ^^^^ required by this bound in `assert_send`
error: aborting due to 1 previous error
For more information about this error, try `rustc --explain E0277`.