Ich habe eine Struktur unsicheren Code mit dem folgenden Verfahren enthalten:Wie autoimplementation von Sync verhindern
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);
}
Diese Struktur ist völlig sicher, bis jemand mit dieser Methode beginnt, während Multithreading. Da die Struktur jedoch nur eine Vec<Box<T,String>>
enthält, ist standardmäßig Sync
implementiert, was ich gerne verhindern würde.
Ich habe zwei Wege gefunden, dies zu tun, die beide nicht so toll ...
ein struct Feld hinzufügen, die nicht
Sync
für*const u8
Beispiel nicht implementiert, das ist offensichtlich eher schlecht, wie es endet in unnötigen und unklaren Code und zeigt nicht deutlich meine Absicht.impl !Sync for Struct {}
ist nicht verfügbar auf stabil und wird nach this issue entfernt werden. Der entsprechende Fehler sagt mir, stattdessen Markertypen zu verwenden, aber the documention bietet auch keine Möglichkeit, mein Problem zu lösen.
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 {}
| ^^^^^^^^^^^^^^^^^^^^^^^^
Bitte versuchen Sie einen [MCVE] bereitzustellen, idealerweise als Link zum Spielplatz. Es ist viel einfacher, die Korrektheit einer Lösung zu testen, wenn man bei dem, was weggelassen wird, nicht raten muss. –
(Beispiel von MCVE: https://play.rust-lang.org/?gist=bcfd5e96cfcd390de67bc738bd821108&version=stable) –
Nein, Ihr Code ist nicht vollständig sicher, auch mit einem einzigen Thread. Es ist UB, ein & T zu einem & mut T zu werfen.Sie sollten UnsafeCell dafür verwenden, was auch Ihr Sync-Problem beheben sollte. – BurntSushi5