💻博主现有专栏:
C51单片机(STC89C516),c语言,c++,离散数学,算法设计与分析,数据结构,Python,Java基础,MySQL,linux,基于HTML5的网页设计及应用,Rust(官方文档重点总结),jQuery,前端vue.js,Javaweb开发,Python机器学习等
🥏主页链接:
目录
Rust 的并发模型中一个有趣的方面是:语言本身对并发知之 甚少。我们之前讨论的几乎所有内容,都属于标准库,而不是语言本身的内容。由于不需要语言提供并发相关的基础设施,并发方案不受标准库或语言所限:我们可以编写自己的或使用别人编写的并发功能。
然而有两个并发概念是内嵌于语言中的:
std::marker
中的Sync
和Send
trait。
🎯通过Send允许在线程间转移所有权
Send
标记 trait 表明实现了Send
的类型值的所有权可以在线程间传送。几乎所有的 Rust 类型都是Send
的,不过有一些例外,包括Rc<T>
:这是不能Send
的,因为如果克隆了Rc<T>
的值并尝试将克隆的所有权转移到另一个线程,这两个线程都可能同时更新引用计数。为此,Rc<T>
被实现为用于单线程场景,这时不需要为拥有线程安全的引用计数而付出性能代价。因此,Rust 类型系统和 trait bound 确保永远也不会意外的将不安全的
Rc<T>
在线程间发送。当尝试在示例 16-14 中这么做的时候,会得到错误the trait Send is not implemented for Rc<Mutex<i32>>
。而使用标记为Send
的Arc<T>
时,就没有问题了。
🎯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>
在运行时所进行的借用检查也不是线程安全的。
🎯手动实现Send和Sync是不安全的
通常并不需要手动实现
Send
和Sync
trait,因为由Send
和Sync
的类型组成的类型,自动就是Send
和Sync
的。因为它们是标记 trait,甚至都不需要实现任何方法。它们只是用来加强并发相关的不可变性的。手动实现这些标记 trait 涉及到编写不安全的 Rust 代码,第十九章将会讲述具体的方法;当前重要的是,在创建新的由不是
Send
和Sync
的部分构成的并发类型时需要多加小心,以确保维持其安全保证。
🎯小结
正如之前提到的,因为 Rust 本身很少有处理并发的部分内容,有很多的并发方案都由 crate 实现。它们比标准库要发展的更快;请在网上搜索当前最新的用于多线程场景的 crate。
Rust 提供了用于消息传递的信道,和像
Mutex<T>
和Arc<T>
这样可以安全的用于并发上下文的智能指针。类型系统和借用检查器会确保这些场景中的代码,不会出现数据竞争和无效的引用。一旦代码可以编译了,我们就可以坚信这些代码可以正确的运行于多线程环境,而不会出现其他语言中经常出现的那些难以追踪的 bug。