如何防止自动执行 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
是默认实现的,我想防止这种情况。
我找到了两种方法,但都不是很好...
添加一个不实现 Sync
的结构字段,例如 *const u8
,这显然是相当糟糕的,因为它最终会导致不必要和不清楚的代码,并且不会清楚表明我的意图。
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
不实现Sync
,Foo<T>
也不会实现Sync
,因此没有必要使用否定实现或任何标记。
1 如果你不直接使用它,你使用的抽象很可能是建立在它之上的。它尽可能特别:它是一个 lang 项目,由其属性 #[lang = "unsafe_cell"]
.
表示
我有一个包含不安全代码的结构,方法如下:
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
是默认实现的,我想防止这种情况。
我找到了两种方法,但都不是很好...
添加一个不实现
Sync
的结构字段,例如*const u8
,这显然是相当糟糕的,因为它最终会导致不必要和不清楚的代码,并且不会清楚表明我的意图。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
不实现Sync
,Foo<T>
也不会实现Sync
,因此没有必要使用否定实现或任何标记。
1 如果你不直接使用它,你使用的抽象很可能是建立在它之上的。它尽可能特别:它是一个 lang 项目,由其属性 #[lang = "unsafe_cell"]
.