trpl-zh-cn/src/ch16-04-extensible-concurrency-sync-and-send.md

41 lines
4.4 KiB
Markdown
Raw Normal View History

## 使用 `Send` 和 `Sync` trait 的可扩展并发
2017-03-22 15:30:00 +08:00
2023-01-24 20:28:25 +08:00
> [ch16-04-extensible-concurrency-sync-and-send.md](https://github.com/rust-lang/book/blob/main/src/ch16-04-extensible-concurrency-sync-and-send.md)
> <br>
> commit 56ec353290429e6547109e88afea4de027b0f1a9
2017-03-22 15:30:00 +08:00
Rust 的并发模型中一个有趣的方面是:我们之前讨论的几乎所有内容,都属于标准库,而不是语言本身的内容。由于不需要语言提供并发相关的基础设施,并发方案不受标准库或语言所限:我们可以编写自己的或使用别人编写的并发功能。
2017-03-22 15:30:00 +08:00
然而,在内嵌于语言而非标准库的关键并发概念中,有属于 `std::marker``Send``Sync` trait。
2017-03-22 15:30:00 +08:00
2018-02-01 17:34:11 +08:00
### 通过 `Send` 允许在线程间转移所有权
2017-03-22 15:30:00 +08:00
`Send` 标记 trait 表明实现了 `Send` 的类型值的所有权可以在线程间传送。几乎所有的 Rust 类型都是`Send` 的,不过有一些例外,包括 `Rc<T>`:这是不能实现 `Send` 的,因为如果克隆了 `Rc<T>` 的值并尝试将克隆的所有权转移到另一个线程,这两个线程都可能同时更新引用计数。为此,`Rc<T>` 被实现为用于单线程场景,这时不需要为拥有线程安全的引用计数而付出性能代价。
2017-03-22 15:30:00 +08:00
因此Rust 类型系统和 trait bound 确保永远也不会意外的将不安全的 `Rc<T>` 在线程间发送。当尝试在示例 16-14 中这么做的时候,会得到错误 `the trait Send is not implemented for Rc<Mutex<i32>>`。而使用实现了 `Send``Arc<T>` 时,就没有问题了。
2017-03-22 15:30:00 +08:00
2024-10-20 23:44:05 +08:00
任何完全由 `Send` 的类型组成的类型也会自动被标记为 `Send`。几乎所有基本类型都是 `Send`除了第二十章将会讨论的裸指针raw pointer
2017-03-22 15:30:00 +08:00
2018-02-01 17:34:11 +08:00
### `Sync` 允许多线程访问
2017-03-22 15:30:00 +08:00
`Sync` 标记 trait 表明一个实现了 `Sync` 的类型可以安全的在多个线程中拥有其值的引用。换一种方式来说,对于任意类型 `T`,如果 `&T``T` 的不可变引用)实现了 `Send` 的话 `T` 就实现了 `Sync`,这意味着其引用就可以安全的发送到另一个线程。类似于 `Send` 的情况,基本类型都实现了 `Sync`,完全由实现了 `Sync` 的类型组成的类型也实现了 `Sync`
2017-03-22 15:30:00 +08:00
智能指针 `Rc<T>` 也没有实现 `Sync`,出于其没有实现 `Send` 相同的原因。`RefCell<T>`(第十五章讨论过)和 `Cell<T>` 系列类型没有实现 `Sync`。`RefCell<T>` 在运行时所进行的借用检查也不是线程安全的。`Mutex<T>` 实现了 `Sync`,正如 [“在线程间共享 `Mutex<T>`”][sharing-a-mutext-between-multiple-threads] 部分所讲的它可以被用来在多线程中共享访问。
2017-03-22 15:30:00 +08:00
2018-02-01 17:34:11 +08:00
### 手动实现 `Send` 和 `Sync` 是不安全的
2017-03-22 15:30:00 +08:00
通常并不需要手动实现 `Send``Sync` trait因为完全由实现了 `Send``Sync` 的类型组成的类型,自动实现了 `Send``Sync`。因为它们是标记 trait甚至都不需要实现任何方法。它们只是用来加强并发相关的不可变性的。
2017-03-22 15:30:00 +08:00
手动实现这些标记 trait 涉及到编写不安全的 Rust 代码,第二十章将会讲述具体的方法;当前重要的是,在创建新的由不是 `Send``Sync` 的部分构成的并发类型时需要多加小心,以确保维持其安全保证。[“The Rustonomicon”][nomicon] 中有更多关于这些保证以及如何维持它们的信息。
2017-03-22 15:30:00 +08:00
## 总结
这不会是本书最后一个出现并发的章节:下一章会我们会专注于异步编程,并且第二十一章的项目会在更现实的场景中使用这些概念,而不像本章中讨论的这些小例子。
2017-03-22 15:30:00 +08:00
正如之前提到的,因为 Rust 本身很少有处理并发的部分内容,有很多的并发方案都由 crate 实现。它们比标准库要发展的更快;请在网上搜索当前最新的用于多线程场景的 crate。
2017-03-22 15:30:00 +08:00
2022-04-22 22:44:07 +08:00
Rust 提供了用于消息传递的信道,和像 `Mutex<T>``Arc<T>` 这样可以安全的用于并发上下文的智能指针。类型系统和借用检查器会确保这些场景中的代码,不会出现数据竞争和无效的引用。一旦代码可以编译了,我们就可以坚信这些代码可以正确的运行于多线程环境,而不会出现其他语言中经常出现的那些难以追踪的 bug。并发编程不再是什么可怕的概念无所畏惧地并发吧
2017-03-22 15:30:00 +08:00
2022-02-10 13:28:50 +08:00
[sharing-a-mutext-between-multiple-threads]: ch16-03-shared-state.html#在线程间共享-mutext
[nomicon]: https://doc.rust-lang.org/nomicon/index.html