【发布时间】:2018-07-18 01:10:58
【问题描述】:
Rust 的 std::sync::Mutex 是一个包含堆分配的 inner 互斥锁的结构,以及这个半神秘的注释:
pub struct Mutex<T: ?Sized> {
// Note that this mutex is in a *box*, not inlined into the struct itself.
// Once a native mutex has been used once, its address can never change (it
// can't be moved). This mutex type can be safely moved at any time, so to
// ensure that the native mutex is used correctly we box the inner mutex to
// give it a constant address.
inner: Box<sys::Mutex>,
poison: poison::Flag,
data: UnsafeCell<T>,
}
评论解释说Box 用于给内部互斥体一个稳定的地址。但我似乎找不到任何解释为什么首先需要一个稳定的地址。
至少在类 Unix 平台上,这里的“本机互斥锁” (sys::Mutex) 最终是 libc::pthread_mutex_t (source code) 的包装。
在 C 中,有一条禁止移动互斥锁的规则几乎是有意义的,因为互斥锁是通过指针使用的,而在有指向它的活动指针时移动它显然是错误的。但是在 Rust 中,你甚至不能尝试移动某些东西,除非 没有对它的实时引用。所以这种说法似乎没有说服力。
为什么原生互斥体必须有一个稳定的地址?
【问题讨论】:
-
我想如果 LLVM 复制该值,则可以毫无问题地移动生锈。
-
还有Can a pthread_mutex_t be moved in memory?。我的重点是:Linux 上的一些互斥锁实现,例如,使用 futex 系统调用,它专门等待 互斥锁的地址
-
@Shepmaster 这似乎是为什么
Mutex不能在锁定时移动的一个很好的理由。但在任何情况下它都不会在锁定时移动,因为MutexGuard在此期间借用它。 futex 限制是否也会影响未锁定的互斥锁? -
@Shepmaster 我认为应该重新讨论这个问题,因为它与关于 std::mutex 的问题并不像起初看起来那样密切相关。具体来说:在 C++ 中,std::mutex 需要担心在它被锁定时被移动。这意味着它需要担心底层系统调用的行为,比如 Linux 上的 futex。 (事实上,由于 futex 将锁的地址作为参数,所以我们绝对不能在锁被锁定时移动它。)但是这个特定的问题不适用于 Rust。相反,Rust 担心的是
pthread_mutex_t可能是自引用的 -
嗯,我想我同意你所说的,@Jack。你会写那个答案吗?