Keyboard shortcuts

Press or to navigate between chapters

Press S or / to search in the book

Press ? to show this help

Press Esc to hide this help


x-i18n: generated_at: “2026-03-01T14:41:41Z” model: gemini-3-flash-preview provider: google-gemini-cli source_hash: 0f8675202aba9f931af209bb9a4cce659af4686719ba54e9c9904ac6fd8264f4 source_path: ch16-04-extensible-concurrency-sync-and-send.md workflow: 16

使用 SendSync 的可扩展并发 (Extensible Concurrency with Send and Sync)

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

Interestingly, almost every concurrency feature we’ve talked about so far in this chapter has been part of the standard library, not the language. Your options for handling concurrency are not limited to the language or the standard library; you can write your own concurrency features or use those written by others.

然而,在嵌入语言本身而非标准库的关键并发概念中,包括 std::marker 特征 SendSync

However, among the key concurrency concepts that are embedded in the language rather than the standard library are the std::marker traits Send and Sync.

在线程间转移所有权 (Transferring Ownership Between Threads)

Transferring Ownership Between Threads

Send 标记特征指示实现 Send 的类型的所有权可以在线程间转移。几乎所有的 Rust 类型都实现了 Send ,但也有一些例外,包括 Rc<T> :它不能实现 Send ,因为如果你克隆了一个 Rc<T> 值并尝试将克隆的所有权转移到另一个线程,这两个线程可能会同时更新引用计数。出于这个原因, Rc<T> 被实现为用于你不希望支付线程安全性能损失的单线程场景。

The Send marker trait indicates that ownership of values of the type implementing Send can be transferred between threads. Almost every Rust type implements Send, but there are some exceptions, including Rc<T>: This cannot implement Send because if you cloned an Rc<T> value and tried to transfer ownership of the clone to another thread, both threads might update the reference count at the same time. For this reason, Rc<T> is implemented for use in single-threaded situations where you don’t want to pay the thread-safe performance penalty.

因此,Rust 的类型系统和特征约束确保了你永远不会意外地在线程间不安全地发送 Rc<T> 值。当我们在示例 16-14 中尝试这样做时,我们得到了错误 the trait `Send` is not implemented for `Rc<Mutex<i32>>`。当我们切换到确实实现了 SendArc<T> 时,代码就通过编译了。

Therefore, Rust’s type system and trait bounds ensure that you can never accidentally send an Rc<T> value across threads unsafely. When we tried to do this in Listing 16-14, we got the error the trait `Send` is not implemented for `Rc<Mutex<i32>>`. When we switched to Arc<T>, which does implement Send, the code compiled.

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

Any type composed entirely of Send types is automatically marked as Send as well. Almost all primitive types are Send, aside from raw pointers, which we’ll discuss in Chapter 20.

从多个线程进行访问 (Accessing from Multiple Threads)

Accessing from Multiple Threads

Sync 标记特征指示实现 Sync 的类型可以从多个线程中安全地引用。换句话说,对于任何类型 T ,如果 &T (对 T 的不可变引用)实现了 Send ,那么 T 就实现了 Sync ,这意味着该引用可以被安全地发送到另一个线程。类似于 Send ,原始类型都实现了 Sync ,完全由实现 Sync 的类型组成的类型也实现了 Sync

The Sync marker trait indicates that it is safe for the type implementing Sync to be referenced from multiple threads. In other words, any type T implements Sync if &T (an immutable reference to T) implements Send, meaning the reference can be sent safely to another thread. Similar to Send, primitive types all implement Sync, and types composed entirely of types that implement Sync also implement Sync.

出于与不实现 Send 相同的原因,智能指针 Rc<T> 也不实现 Sync 。我们在第 15 章谈到的 RefCell<T> 类型和相关的 Cell<T> 家族类型不实现 SyncRefCell<T> 在运行时进行的借用检查实现不是线程安全的。智能指针 Mutex<T> 实现了 Sync ,可以用于在多个线程间共享访问,正如你在“多线程共享 Mutex<T>中看到的。

The smart pointer Rc<T> also doesn’t implement Sync for the same reasons that it doesn’t implement Send. The RefCell<T> type (which we talked about in Chapter 15) and the family of related Cell<T> types don’t implement Sync. The implementation of borrow checking that RefCell<T> does at runtime is not thread-safe. The smart pointer Mutex<T> implements Sync and can be used to share access with multiple threads, as you saw in “Shared Access to Mutex<T>.

手动实现 SendSync 是不安全的 (Implementing Send and Sync Manually Is Unsafe)

Implementing Send and Sync Manually Is Unsafe

因为完全由实现了 SendSync 特征的其他类型组成的类型会自动实现 SendSync ,所以我们不需要手动实现这些特征。作为标记特征,它们甚至没有任何方法需要实现。它们只是对于强制执行与并发相关的各种不变量很有用。

Because types composed entirely of other types that implement the Send and Sync traits also automatically implement Send and Sync, we don’t have to implement those traits manually. As marker traits, they don’t even have any methods to implement. They’re just useful for enforcing invariants related to concurrency.

手动实现这些特征涉及实现不安全的 Rust 代码。我们将在第 20 章谈论使用不安全的 Rust 代码;目前,重要的信息是构建不完全由 SendSync 部分组成的新并发类型需要仔细考虑以维护安全保证。“The Rustonomicon” 中有更多关于这些保证以及如何维护它们的信息。

Manually implementing these traits involves implementing unsafe Rust code. We’ll talk about using unsafe Rust code in Chapter 20; for now, the important information is that building new concurrent types not made up of Send and Sync parts requires careful thought to uphold the safety guarantees. “The Rustonomicon” has more information about these guarantees and how to uphold them.

总结 (Summary)

这不是你在本书中最后一次看到并发:下一章将重点讨论异步编程,第 21 章中的项目将会在比这里讨论的小例子更实际的场景中使用本章的概念。

This isn’t the last you’ll see of concurrency in this book: The next chapter focuses on async programming, and the project in Chapter 21 will use the concepts in this chapter in a more realistic situation than the smaller examples discussed here.

如前所述,由于 Rust 处理并发的方式只有极少部分是语言的一部分,许多并发解决方案都是作为 crate 实现的。这些演进速度比标准库快,因此在多线程场景下,务必在网上搜索当前最先进的 crate。

As mentioned earlier, because very little of how Rust handles concurrency is part of the language, many concurrency solutions are implemented as crates. These evolve more quickly than the standard library, so be sure to search online for the current, state-of-the-art crates to use in multithreaded situations.

Rust 标准库为消息传递提供了通道,并提供了智能指针类型,如 Mutex<T>Arc<T> ,它们在并发上下文中是安全的。类型系统和借用检查器确保使用这些解决方案的代码不会以竞态条件或无效引用告终。一旦你的代码通过编译,你就可以放心,它将在多线程上愉快地运行,而不会出现其他语言中常见的那些难以追踪的 bug。并发编程不再是一个令人恐惧的概念:去吧,让你的程序无畏地并发运行!

The Rust standard library provides channels for message passing and smart pointer types, such as Mutex<T> and Arc<T>, that are safe to use in concurrent contexts. The type system and the borrow checker ensure that the code using these solutions won’t end up with data races or invalid references. Once you get your code to compile, you can rest assured that it will happily run on multiple threads without the kinds of hard-to-track-down bugs common in other languages. Concurrent programming is no longer a concept to be afraid of: Go forth and make your programs concurrent, fearlessly!