`mem :: swap`ing`Mutex <t>`真的安全吗?

时间:2016-02-26 12:59:47

标签: rust

一个简单的例子:

use std::mem;
use std::sync::{Mutex};

fn main() {
    let mut orig = Mutex::new(vec![1, 2, 3]);
    let mut other = Mutex::new(vec![]);
    mem::swap(&mut orig, &mut other);
    println!("{:?}", other);
}

据Rust说,这个程序非常安全。然而swap(或replace)的实现并不试图锁定任何东西。来自source

#[inline]
#[stable(feature = "rust1", since = "1.0.0")]
pub fn swap<T>(x: &mut T, y: &mut T) {
    unsafe {
        // Give ourselves some scratch space to work with
        let mut t: T = uninitialized();

        // Perform the swap, `&mut` pointers never alias
        ptr::copy_nonoverlapping(&*x, &mut t, 1);
        ptr::copy_nonoverlapping(&*y, x, 1);
        ptr::copy_nonoverlapping(&t, y, 1);

        // y and t now point to the same thing, but we need to completely
        // forget `t` because we do not want to run the destructor for `T`
        // on its value, which is still owned somewhere outside this function.
        forget(t);
    }
}

MutexAtomic变量使用非同步访问似乎是一个麻烦的方法,这样安全吗?如果是,为什么?

2 个答案:

答案 0 :(得分:8)

MutexSync,这意味着允许多个线程同时访问同一个对象。首先可以跨线程共享单个对象的类型(Arc,还有全局变量)需要确保它们共享的对象为Sync以确保完整性。

但是,这并不能避免Rust的其他别名规则。具体来说,在任何给定时间只能存在一个mut的变量借位,并且它的存在必须阻止对该变量的任何其他访问。使分享成为可能的事情也必须确保这一点。 Arc通过简单地永远不会将mut引用分发给它的指针来实现这一点;你只能得到非mut个引用。这就是Mutex::lock占用&self的原因:必须可以在非mut引用上调用它。同样,Atomic*::store和所有其他操作方法都需要&self。另一方面,static mut变量只能在不安全的代码中访问,程序员负责维护保证。

mem::swap需要mut个引用。当编译器允许您将两个Mutex对象传递给swap时,这意味着您从未与其他线程共享互斥体 - 您既不会将它们放入Arc,也不会将它们放入staticmut(不是static mut)或swap(除非您处于不安全的代码中)。

因此,{{1}}是安全的,因为您在一个帖子中执行此操作。

答案 1 :(得分:3)

答案很简单:可变性XOR别名。

为什么mem::swap安全,尽管没有锁定互斥锁或执行原子操作?

因为&mut TT保证在编译时没有可访问的别名。

MutexAtomicXXX在线程共享时通过限制类型和操作(AtomicXXX)或确保&#34; Mutability XOR Aliasing&而实现安全突变的事实#34;在运行时(Mutex)是编译时保证的一个例外,但它不会取代它。

可以安全地改变类型:

  • 如果在编译时没有别名(&mut TT
  • 如果在运行时,该类型的特殊属性确保这是安全的

具有特殊属性的类型按照<{1}}和mem::swap的安全性所依赖的常规编译时规则在>上进行,因此在情况下如果没有别名可以在编译时证明,它们可以在没有任何特定同步的情况下进行变异。