介绍
本系列录制的视频主要放在B站上Rust死灵书学习视频
Rust 死灵书相关的源码资料在github.com/anonymousGiga/Rustonomi...
Send和Sync
当同一块内存有多个别名,同时还可以改变内存的值的时候,它们就不是线程安全的。
Rust中根据Send和Sync trait获取相关的信息:
1、如果一个类型可以安全地传递给另一个线程,那么这个类型是实现了Send这个trait了的;
2、如果一个类型可以安全地被多个线程共享,那么这个类型就是Sync的。
Send和Sync是Rust并发机制的基础,但是它们是非安全的trait。Send和Sync是标志trait(即没有任何关联方法),类型要实现它们其实就是满足它们需要的内部特征。不正确的实现Send和Sync会导致未定义行为。
Send和Sync是自动推到的trait,规则:
1、如果一个类型完全由Send或者Sync组成,那么这个类型本身也是Send或者Sync的;
2、几乎所有的基本类型都是Send和Sync的。
例外情况:
1、裸指针不是Send的,也不是Sync的;
2、UnsafeCell不是Sync的(Cell和RefCell也不是);
3、Rc不是Send或Sync的(引用计数是共享且非同步的)。
Rc和UnsafeCell是典型的非线程安全的,因为它们允许非同步地共享可变状态。
不能自动推导的类型也可以很容易的实现Send和Sync:
struct MyBox(*mut u8);
unsafe impl Send for MyBox {}
unsafe impl Sync for MyBox {}
还有一个比较少见的场景,一个类型被自动推导为Send或者Sync,但它其实不满足二者的要求,此时我们可以为其去掉Send和Sync的实现,方式如下:
#![feature(negative_impls)]
// I have some magic semantics for some synchronization primitive!
struct SpecialThreadToken(u8);
impl !Send for SpecialThreadToken {}
impl !Sync for SpecialThreadToken {}
这里需要注意的是,一种类型自己不可能被不正确的推导为Send和Sync,只有类型和其它非安全代码一起实现一些特殊行为时,才可能成为一个不正确的Send或者Sync。