You can not select more than 25 topics
Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
This file contains ambiguous Unicode characters that may be confused with others in your current locale. If your use case is intentional and legitimate, you can safely ignore this warning. Use the Escape button to highlight these characters.
## 使用`Sync`和`Send` trait 的可扩展并发
> [ch16-04-extensible-concurrency-sync-and-send.md](https://github.com/rust-lang/book/blob/master/second-edition/src/ch16-04-extensible-concurrency-sync-and-send.md)
> <br>
> commit 9430a3d28a2121a938d704ce48b15d21062f880e
Rust 的并发模型中一个有趣的方面是:语言本身对并发知之**甚少**。我们之前讨论的几乎所有内容,都属于标准库,而不是语言本身的内容。由于不需要语言提供并发相关的基础设施,并发方案不受标准库或语言所限:我们可以编写自己的或使用别人编写的。
我们说“**几乎**所有内容都不属于语言本身”,那么属于语言本身的是什么呢?是两个 trait, 都位于`std::marker`: `Sync` 和`Send`。
### `Send`用于表明所有权可能被传送给其他线程
`Send` 标记 trait 表明类型的所有权可能被在线程间传递。几乎所有的 Rust 类型都是`Send`的,不过有一些例外。比如标准库中提供的 `Rc<T>` :如果克隆`Rc< T > `值,并尝试将克隆的所有权传递给另一个线程,这两个线程可能会同时更新引用计数。正如上一部分提到的,`Rc< T > `被实现为用于单线程场景,这时不需要为拥有线程安全的引用计数而付出性能代价。
因为 `Rc<T>` 没有标记为 `Send` , Rust 的类型系统和 trait bound 会确保我们不会错误的把一个 `Rc<T>` 值不安全的在线程间传递。列表 16-14 曾尝试这么做,不过得到了一个错误,`the trait Send is not implemented for Rc< Mutex < i32 > >`。而使用标记为 `Send` 的 `Arc<T>` 时,就没有问题了。
任何完全由 `Send` 的类型组成的类型也会自动被标记为 `Send` :几乎所有基本类型都是 `Send` 的,大部分标准库类型是`Send`的,除了`Rc< T > `, 以及第十九章将会讨论的裸指针( raw pointer) 。
### `Sync` 表明多线程访问是安全的
`Sync` 标记 trait 表明一个类型可以安全的在多个线程中拥有其值的引用。换一种方式来说,对于任意类型 `T` ,如果`& T`( `T`的引用)是`Send`的话`T`就是`Sync`的,这样其引用就可以安全的发送到另一个线程。类似于 `Send` 的情况,基本类型是 `Sync` 的,完全由 `Sync` 的类型组成的类型也是 `Sync` 的。
`Rc<T>` 也不是 `Sync` 的,出于其不是`Send`的相同的原因。`RefCell< T > `(第十五章讨论过)和`Cell< T > `系列类型不是`Sync`的。`RefCell< T > `在运行时所进行的借用检查也不是线程安全的。`Mutex< T > `是`Sync`的,正如上一部分所讲的它可以被用来在多线程中共享访问。
### 手动实现`Send`和`Sync`是不安全的
通常并不需要实现`Send`和`Sync` trait, 由属于`Send`和`Sync`的类型组成的类型,自动就是`Send`和`Sync`的。因为他们是标记 trait, 甚至都不需要实现任何方法。他们只是用来加强并发相关的不可变性的。
实现这些标记 trait 涉及到编写不安全的 Rust 代码,第十九章将会讲述具体的方法;当前重要的是,在创建新的由不是`Send`和`Sync`的部分构成的并发类型时需要多加小心,以确保维持其安全保证。[The Nomicon] 中有更多关于这些保证以及如何维持他们的信息。
[The Nomicon]: https://doc.rust-lang.org/stable/nomicon/
## 总结
这不会是本书最后一个出现并发的章节;第二十章的项目会在更现实的场景中使用这些概念,而不像本章中讨论的这些小例子。
正如我们提到的,因为 Rust 本身很少有处理并发的部分内容,有很多的并发方案都由 crate 实现。他们比标准库要发展的更快;请在网上搜索当前最新的用于多线程场景的 crate。
Rust 提供了用于消息传递的通道,和像`Mutex< T > `和`Arc< T > `这样可以安全的用于并发上下文的智能指针。类型系统和借用检查器会确保这些场景中的代码,不会出现数据竞争和无效的引用。一旦代码可以编译了,我们就可以坚信这些代码可以正确的运行于多线程环境,而不会出现其他语言中经常出现的那些难以追踪的 bug。并发编程不再是什么可怕的概念: 无所畏惧地并发吧!
接下来,让我们讨论一下当 Rust 程序变得更大时,有哪些符合语言习惯的问题建模方法和结构化解决方案,以及 Rust 的风格是如何与面向对象编程( Object Oriented Programming) 中那些你所熟悉的概念相联系的。