Rust 学习笔记:通过 Send 和 Sync trait 实现可扩展并发性
Rust 学习笔记:通过 Send 和 Sync trait 实现可扩展并发性
处理并发的选项并不局限于语言或标准库。
你可以编写自己的并发特性,也可以使用其他人编写的并发特性。
Send 和 Sync trait 是 Rust 标准库下的 marker trait。
Send trait:允许在线程之间转移所有权
Send trait 表明实现 Send 的类型的值的所有权可以在线程之间转移。
几乎每个 Rust 类型都是 Send,但也有一些例外,比如 Rc<T>。
Rc<T> 不能实现 Send,因为如果你克隆了一个 Rc<T> 值,并试图将克隆的所有权转移给另一个线程,两个线程可能同时更新引用计数。出于这个原因,Rc<T> 是为在单线程情况下使用而实现的。
Rust 的类型系统和 trait 约束确保不会将非 Send 类型跨线程发送。
任何完全由 Send 类型组成的类型也会自动标记为 Send。
几乎所有基本类型都实现了 Send,原始指针除外。
Sync trait:允许多线程访问
Sync trait 表明,从多个线程引用实现 Sync 的类型是安全的。
换句话说,如果 &T(对 T 的不可变引用)实现了 Send,则任何类型 T 都实现了 Sync,这意味着引用可以安全地发送到另一个线程。
与 Send 类似,基本类型都实现了 Sync,完全由实现 Sync 的类型组成的类型也实现了 Sync。
智能指针小结:
- Rc<T>:没有实现 Send,也没有实现 Sync。
- RefCell<T>:实现 Send(如果 T 实现 Send),没有实现 Sync。在运行时执行的借用检查的实现不是线程安全的。
- Mutex<T>:实现了 Send 和 Sync,可以用于与多个线程共享访问。
- MutexGuard<'a, T>:实现 Sync(如果 T 实现 Sync),没有实现 Send。
手动实现 Send 和 Sync 是不安全的
因为完全由实现 Send 和 Sync 的其他类型组成的类型也会自动实现 Send和 Sync,所以我们不需要手动实现这些特性。
作为 marker trait,它们甚至没有任何方法来实现。它们只是用于执行与并发相关的不变量。
手动实现这些特征涉及实现 unsafe 的 Rust 代码。构建不由 Send 和 Sync 部分组成的新并发类型需要仔细考虑以维护安全保证。
练习题
参考视频:
- https://www.bilibili.com/video/BV1LdovYrEVw
假设你正在设计一个数据库连接的 API:
struct DbConnection { /* ... */ }
impl DbConnection {
fn query(&self) -> DbResult {
/* ... */
}
}
你的数据库不支持从同一连接进行并发查询。DbConnection 应该实现哪些 marker trait?
答:Send。