Multithreading 如何防止自动执行同步
我有一个包含以下方法的不安全代码的结构:Multithreading 如何防止自动执行同步,multithreading,struct,rust,traits,unsafe,Multithreading,Struct,Rust,Traits,Unsafe,我有一个包含以下方法的不安全代码的结构: 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 !(
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);
}
Rust中的内部易变性要求使用1作为一个提示,提示编译器正常规则不适用 因此,您的结构应如下所示:
#[derive(Debug)]
struct Foo<T> {
items: UnsafeCell<Vec<Box<(T, String)>>>,
}
使用UnsafeCell
使得change\u mut
完全没有必要:毕竟,UnsafeCell
的目的是允许内部可变性。请注意它的get
方法如何返回原始指针,如果没有不安全的块,就无法取消引用该指针
由于UnsafeCell
没有实现Sync
,Foo
也不会实现Sync
,因此没有必要使用否定实现或任何标记
1如果您不直接使用它,那么您使用的抽象很可能是建立在它之上的。它尽可能的特殊:它是一个lang项目,由其属性#[lang=“unsafe_cell”]
表示。请尝试提供一个链接,理想情况下作为到操场的链接。如果不必猜测省略了什么,那么测试解决方案的正确性就容易多了。(MCVE的示例:)不,即使使用单个线程,代码也不是完全安全的。将an&T转换为a&mut T是非常困难的。您应该为此使用UnsafeCell,这也可以解决您的同步问题。@BurntSushi5您可能需要加入:-)
#[derive(Debug)]
struct Foo<T> {
items: UnsafeCell<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 { &mut *self.items.get() };
// ^~~~~~~~~~~~~~~~~~~~~~
items.push(Box::new((element,key)));
}
}
}