Rust-线程:使用Sync和Send trait的可扩展并发

Rust的并发模型中一个有趣的方面是:语言本身对并发知之甚少。我们之前讨论的几乎所有内容,都属于标准库,而不是语言本身的内容。由于不需要语言提供并发相关的基础设施,并发方案不受标准库或语言所限:我们可以编写自已的或使用别人编写的并发功能。

然而有两个并发概念是内嵌于语言中的:std::marker 中的 SyncSend trait。

通过Send允许在线程间转移所有权

Send标记trait表明类型的所有权可以在线程间传递。几乎所有的Rust类型都是Send的,不过有一些例外,包括Rc<T>: 这是不能Send的,因为如果克隆了Rc<T>的值并尝试将克隆的所有权转移到另一个线程,这两个线程都可能同时更新引用计数。为此,Rc<T>被实现为用于单线程场景,这时不需要为拥有线程安全的引用计数而付出性能代价。

因此,Rust类型系统和trait bound确保永远也不会意外的将不安全的Rc<T>在线程间发送。

任何完全由Send的类型组成的类型也会自动被标记为Send。几乎所有基本类型都是Send的,除了裸指针(raw pointer)。

Sync允许多线程访问

Sync标记trait表明一个实现了Sync的类型可以安全的在多个线程中拥有其值的引用。换一种方式来说,对于任意类型T,如果 &T (T的引用)是Send的话T就是Sync的,这意味着其引用就可以安全的发送到另一个线程。类似于Send的情况,基本类型是Sync的,完全由Sync的类型组成的类型也是Sync的。

智能指针Rc<T>也不是Sync的,出于其不是Send相同的原因。RefCell<T>和Cell<T>系列类型不是Sync的。RefCell<T>在运行时所进行的借用检查也不是线程安全的。Mutex<T>是Sync的,正如"在线程间共享Mutex<T>"部分所讲的它可以被用来在多线程中共享访问。

手动实现Send和Sync是不安全的

通常并不需要手动实现SendSync trait,因为由Send和Sync的类型组成的类型,自动就是Send和Sync的。因为他们是标记trait,甚至都不需要实现任何方法。他们只是用来加强并发相关的不可变性的。

posted @ 2021-10-07 17:15  johnny_zhao  阅读(314)  评论(0编辑  收藏  举报