深入浅出Rust(第四部分)


传送门:
深入浅出Rust(第一部分-1)
深入浅出Rust(第一部分-2)
深入浅出Rust(第二部分-1)
深入浅出Rust(第二部分-2)
深入浅出Rust(第三部分-1)
深入浅出Rust(第三部分-2)
深入浅出Rust(第四部分)
深入浅出Rust(第五部分)


第四部分 - 线程安全

Rust在编译器层面做了很多工作,进而在编译过程就发现和阻止线程不安全的情形

第27章 线程安全

1. 什么是线程

2. 启动线程

thread::spawn(MOVE ||{
    //线程内部逻辑
});

相当于做了闭包代码块

Thead模块常用API:

  • thread::sleep(dur: Duration)
  • thread::yield_now()
  • thread::current()
  • thread::park()
  • thread::Thread::unpark(&self)

3. 避免数据竞争

直接传mut变量,copy类型进去,都会造成编译错误.

4. send & Sync

Rust正是通过这两个特殊的trait,对线程安全进行了控制

pub fn spawn<F,T>(f: F) -> JoinHandle<T>
    where F: FnOne() -> T, F:Send + 'static, T: Send +'static

从spawn的函数签名可以参数,F和T需要满足Send trait,因此在线程间传递所有权会发生安全问题的类型,Rust就能检测出来.

第28章 详解Send和Sync

1. 什么是Send

  • Send trait满足不同线程间传递所有权是安全的
  • 包括基本类型,内部不含引用的类型(string),泛型参数满足的(Cell<T>,RefCell<T>,Mutex<T>)
  • 不包括RC<T>

2. 什么是Sync

  • Sync trait满足不同线程使用&T访问同一变量
  • 包括基本类型,泛型参数满足的(Box<T>,Vec<T>,Mutex<T>)
  • 不包括Cell<T>,RefCell<T>

3. 自动推理

  • 实际上 Send和Sync都是std::marker模块的特殊trait,用户不用手写impl,而是编译器自动完成
  • 如果要自己写,一定要配合unsafe关键字,并且自己保证其安全性

第29章 状态共享

1. ARC

  • Arc是Rc的线程安全版本
29-1.png

2. Mutex(重点)

  • Mutex提供安全的内部可变性(通过lock()调用)
  • lock()方法返回LockResult类型,
type LockResult<Guard> = Result<Guard, PoisonError<Guard>>;

如果lock过程发生了panic,那么这个Mutex则变为"有毒"状态.

3. RwLock

  • RwLock和使用类似Mutex,相对来说,更不严格一点,可以通过read实现共享,write实现独占.

4. Atomic

  • Atomic系列类型提供了"原子操作",因此他们都是符合Sync的,可以在多线程间共享使用.
  • 修改时要用fetch_add()和fetch_sub()实现原子化的数据增减,而load,store本身虽然原子化,但是无法保证两个操作之间的原子化.

5. 死锁

  • rust并不保证线程间不出现死锁,这个需要程序员自行完善逻辑

6. Barrier

  • Barrier类似waitgroup,当条件完全满足才能继续

7. Condvar(重点)

  • Condvar通常与Mutex配套使用,用来在线程之前进行消息传递,从而进行手工同步
29-2.png

8. 全局变量

  • 全局变量显然不适合用在多线程里,太容易造成线程不安全了.
  • mut全局变量基本无法满足Send,Sync约束
  • 可以用atomic型全局变量(限定为简单的i32)

9. 线程局部存储

  • threalocal!{}宏声明,××.with{}限定使用范围.
  • java也一样这么搞的

第30章 管道

显然,Rust的channel比起Go,还是有差距的.

1. 异步管道

  • 异步管道(std::sync::mpsc::channel),实现管道的异步读写(不需要考虑管道本身大小)
  • Send和Receiver都必须满足T: Send约束.
  • 可以实现多发单收

2. 同步管道

  • 异步管道(std::sync::mpsc::sync_channel),实现管道的同步读写(管道大小为1)

第31章 第三方并行开发库

1. threadpool

  • new出大小,execute执行

2. scoped-threadpool

  • 线程内部直接使用&mut访问父线程变量,而不需用Arc包装

3. parking_lot

  • 实现另外一套同步原语(Mutex,CondVar)

4. crossbeam

  • 实现了双端管道

5. rayon

31-1.png
  • 实现了并行迭代器和join()

推荐阅读更多精彩内容