如何防止自动执行 Sync

How to prevent autoimplementation of Sync

我有一个包含不安全代码的结构,方法如下:

use std::sync::Arc;
use std::thread;

#[derive(Debug)]
struct Foo<T> {
    items: Vec<Box<(T, String)>>,
}

impl<T> Foo<T> {
    pub fn add_element(&self, element: T, key: String) {
        if !(self.items.iter().any( |i| i.1 == key)) {
            let mut items = unsafe {change_mut(&(self.items))};
            items.push(Box::new((element,key)));
        }
    }
}

unsafe fn change_mut<T>(x: &T) -> &mut T { // changes &self to &mut self
    &mut *(x as *const T as *mut T)
}

fn main() {
    let foo = Arc::new(Foo { items: vec!() });
    let clone = foo.clone();

    // This should not be possible, as it might lead to UB
    thread::spawn(move || clone.add_element(1, String::from("one")));

    println!("{:?}", *foo);

}

在有人开始在多线程中使用此方法之前,此结构是完全安全的。但是,由于该结构仅包含一个 Vec<Box<T,String>>Sync 是默认实现的,我想防止这种情况。

我找到了两种方法,但都不是很好...

  1. 添加一个不实现 Sync 的结构字段,例如 *const u8,这显然是相当糟糕的,因为它最终会导致不必要和不清楚的代码,并且不会清楚表明我的意图。

  2. impl !Sync for Struct {} 在稳定版上不可用,将根据 this issue 删除。 相应的错误告诉我改用标记类型,但 the documention 也没有提供解决我的问题的方法。


error: negative trait bounds are not yet fully implemented; use marker types for
 now (see issue #13231)
  --> src\holder.rs:44:1
   |
44 | impl !Sync for Struct {}
   | ^^^^^^^^^^^^^^^^^^^^^^^^

Rust 中的内部可变性 需要1 使用 UnsafeCell 作为对编译器的提示,正常规则 不适用.

因此您的结构应该如下所示:

#[derive(Debug)]
struct Foo<T> {
    items: UnsafeCell<Vec<Box<(T, String)>>>,
}

然后,add_element的实现调整为:

impl<T> Foo<T> {
    pub fn add_element(&self, element: T, key: String) {
        if !(self.items.iter().any( |i| i.1 == key)) {
            let mut items = unsafe { &mut *self.items.get() };
            //                       ^~~~~~~~~~~~~~~~~~~~~~
            items.push(Box::new((element,key)));
        }
    }
}

UnsafeCell 的使用使得 change_mut 完全没有必要:毕竟,UnsafeCell 的目的是允许内部可变性。请注意它的 get 方法如何 returns 一个原始指针,如果没有 unsafe 块就无法取消引用。


由于UnsafeCell不实现SyncFoo<T>也不会实现Sync,因此没有必要使用否定实现或任何标记。


1 如果你不直接使用它,你使用的抽象很可能是建立在它之上的。它尽可能特别:它是一个 lang 项目,由其属性 #[lang = "unsafe_cell"].

表示