使用 Send 和 Sync 实现可扩展并发

Beginner

This tutorial is from open-source community. Access the source code

💡 本教程由 AI 辅助翻译自英文原版。如需查看原文,您可以 切换至英文原版

简介

欢迎来到「使用 Send 和 Sync 特性实现可扩展并发」实验。本实验是 Rust 程序设计语言 的一部分。你可以在 LabEx 中练习 Rust 技能。

在本实验中,我们将探索 Rust 中的两个并发概念——SendSync 特性,它们提供了超越标准库的可扩展并发能力。

使用 Send 和 Sync 特性实现可扩展并发

有趣的是,Rust 语言本身的并发特性非常少。到目前为止,我们在本章中讨论的几乎每个并发特性都是标准库的一部分,而不是语言本身的特性。你处理并发的选项不限于语言或标准库;你可以编写自己的并发特性,或者使用其他人编写的特性。

然而,语言中嵌入了两个并发概念:std::marker 特性 SendSync

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

Send 标记特性表明,实现了 Send 的类型的值的所有权可以在线程间转移。几乎所有的 Rust 类型都是 Send,但也有一些例外,包括 Rc<T>:它不能是 Send,因为如果你克隆一个 Rc<T> 值并试图将克隆的所有权转移到另一个线程,两个线程可能会同时更新引用计数。因此,Rc<T> 用于不需要承担线程安全性能开销的单线程场景。

因此,Rust 的类型系统和 trait 边界确保你永远不会意外地在线程间不安全地发送 Rc<T> 值。当我们在清单 16-14 中尝试这样做时,我们得到了错误 the trait Sendis not implemented forRc<Mutex>}。当我们切换到 Arc<T>(它是 Send)时,代码编译通过。

任何完全由 Send 类型组成的类型也会自动被标记为 Send。除了原始指针(我们将在第 19 章讨论)之外,几乎所有的原始类型都是 Send

通过 Sync 允许从多个线程进行访问

Sync 标记特性表明,对于实现了 Sync 的类型,从多个线程引用它是安全的。换句话说,如果 &T(对 T 的不可变引用)是 Send,则任何类型 T 就是 Sync,这意味着该引用可以安全地发送到另一个线程。与 Send 类似,原始类型是 Sync,并且完全由 Sync 类型组成的类型也是 Sync

智能指针 Rc<T> 由于与它不是 Send 相同的原因,也不是 SyncRefCell<T> 类型(我们在第 15 章讨论过)以及相关的 Cell<T> 类型家族都不是 SyncRefCell<T> 在运行时进行的借用检查实现不是线程安全的。智能指针 Mutex<T>Sync,并且正如你在“在多个线程之间共享 Mutex<T>”中看到的,可以用于与多个线程共享访问。

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

由于由 SendSync 特性组成的类型会自动也是 SendSync,所以我们不必手动实现这些特性。作为标记特性,它们甚至没有任何方法需要实现。它们只是有助于强制实施与并发相关的不变性。

手动实现这些特性涉及编写不安全的 Rust 代码。我们将在第 19 章讨论使用不安全的 Rust 代码;目前,重要的信息是,构建不由 SendSync 部分组成的新并发类型需要仔细考虑以维护安全保证。位于 https://doc.rust-lang.org/stable/nomicon 的《Rustonomicon》有关于这些保证以及如何维护它们的更多信息。

总结

恭喜你!你已经完成了“使用 Send 和 Sync 特性实现可扩展并发”实验。你可以在 LabEx 中练习更多实验来提升你的技能。

您可能感兴趣的其他 教程