Rust Send Sync

本贴最后更新于 479 天前,其中的信息可能已经渤澥桑田

整理自 2023-09-04 群 telegram 上 Rust 众聊天记录,针对 Sync 与 Send 之间的讨论

理解

Sync

指的是允许 &T 暴露给多线程,一个类型支持 Sync,可以看成这个类型看作 &T

Send

指的是允许 &mut T 或者 T 暴露给多线程,一个类型支持 Send,可以把这个类型看作 &mut T

从 thread spawn capture 的角度来看为什么这么分类

compound type 内嵌的东西拆分出来,直接就相当于是一共三种: T, &mut T, &T, 三种分别约束一下是否允许带走。推理一下可知 T 和 &mut T 是否允许带走是一回事,所以只剩下 &T 不太一样,然后把这种情况放在 T 上单独取名叫 Sync。

——Carl Lei

Q1 Send 是否可以替代 Sync?

A1: 不能,Send 的作用类似 &mut T 但是他并不是真的就是 &mut T。Send 的重点在 &mut T 能不能暴露给多线程,而不是 Send 代表 &mut T。同理, Sync 的作用是指的 &T 能不能暴露给多线程,并不是 Sync 代表 &T

所以 T: Sync 的含义是,&T 可以在多线程之间暴露。所以 T: Sync <=> &T: Send

Q2 为什么实现 Mutex Sync 需要 T Send

impl<T: ?Sized + Send> Sync for Mutex<T>

MutexSync 的,相当于 Mutex 只要传递 &Mutex,那为什么需要内部的 T 实现 Send

A2:

**Mutex 只是用来防 race, 不能违反其他安全约束的。**所以如果你想 Send &Mutex, 那因为你能从这得到 &mut T 所以就只能在 &mut T 也是 Send 的情况下才可以。然后 &mut T: Send 也就是 T: Send, 整个约束简化一下就是 Mutex: Sync where T: Send。——Carl Lei

但是我觉得上面这个说法虽然解释地十分精彩并简练,但是对新手来说不够详尽,所以做了一些补充。

Mutex<T> 存在一个 lock 方法,其返回的是 LockResult<MutexGuard<T>>,其中重点是 MutexGuard<T>,它实现了 DeferMut 的 trait。DeferMut 返回了 &mut T。所以要求必须是 T: Send

Q3 为什么 MutexGuard 是!Send 的

A3: MutexGuard 假如 Send 的话,就代表 &mut MutexGuard,也就是 MutexGuard 可以在多线程之中被修改。而 Mutex 的设计要求 lockunlock() 必须在一个线程,所以是 !Send 的。——布丁

Q4 解释为什么 Arc Send 需要 T Send + Sync

A4:

假设我是传给 thread spawn 的一个 closure, 我拥有一个 Arc:

  1. 我可以从 Deref 拿到一个 &T, 所以我得保证 &T: Send;
  2. 我 drop 这个 Arc 的时候可能执行到 T::drop 进而隐式的导致 &mut T 出现在我执行中的线程上,所以要保证 &mut T: Send.

还是引用的 Carl Lei 的回答。

还是针对新手在第二点上做一个补充,Arc 是通过 Arc::new(T) 而来,T 的所有权被传递到 Arc 中。当 Arc 被彻底 drop 的时候,会同时 drop 掉 T,所以需要 T 是&mut 的。

Q5 rc 为什么既不 Send 也不 Sync

首先它不 send 因为不是 atomic,引用计数可能出问题 ——布丁

sync 你拿一个&Rc 到别的 thread 去 clone 那不就 effectively 是 send 了,甚至不需要 只要是 clone 就会碰引用计数 就有可能 data race ——pop

  • Rust

    Rust 是一门赋予每个人构建可靠且高效软件能力的语言。Rust 由 Mozilla 开发,最早发布于 2014 年 9 月。

    58 引用 • 22 回帖
1 操作
ssfdust 在 2023-09-04 15:57:32 更新了该帖

相关帖子

欢迎来到这里!

我们正在构建一个小众社区,大家在这里相互信任,以平等 • 自由 • 奔放的价值观进行分享交流。最终,希望大家能够找到与自己志同道合的伙伴,共同成长。

注册 关于
请输入回帖内容 ...