2016-04-15 26 views
5

I-Code, der ein RefCell erzeugt und dann auf diese RefCell einen Verweis übergeben will einen einzigen thread:Wie kann ich garantieren, dass ein Typ, der keine Synchronisation implementiert, tatsächlich sicher zwischen Threads geteilt werden kann?

extern crate crossbeam; 

use std::cell::RefCell; 

fn main() { 
    let val = RefCell::new(1); 

    crossbeam::scope(|scope| { 
     scope.spawn(|| *val.borrow()); 
    }); 
} 

Im kompletten Code, ich bin mit einem Typ, der ein RefCell in eingebettet ist es (a typed_arena::Arena). Ich verwende crossbeam, um sicherzustellen, dass der Thread die Referenz nicht überlebt.

Dies erzeugt den Fehler:

error: the trait bound `std::cell::RefCell<i32>: std::marker::Sync` is not satisfied [E0277] 

    scope.spawn(|| *val.borrow()); 
      ^~~~~ 

Ich glaube, ich verstehe, warum dieser Fehler passiert: RefCell nicht gleichzeitig zu aufzuziehen ist von mehreren Threads aufgerufen, und da es verwendet interne Veränderlichkeit, den normalen Mechanismus der ein erfordern Single Mutable Borrow wird nicht mehrere gleichzeitige Aktionen verhindern. Dies wird auch dokumentiert auf Sync:

Types that are not Sync are those that have "interior mutability" in a non-thread-safe way, such as Cell and RefCell in std::cell .

Das ist alles schön und gut, aber in diesem Fall, ich weiß, dass nur ein Thread der Lage ist, die RefCell zuzugreifen. Wie kann ich dem Compiler bestätigen, dass ich verstehe, was ich mache, und ich stelle sicher, dass dies der Fall ist? Natürlich, wenn meine Schlussfolgerung, dass dies tatsächlich sicher ist, falsch ist, würde ich mehr als glücklich sein, warum ich das erfahren würde.

Antwort

2

Nun, wäre eine Möglichkeit, einen Wrapper mit einem unsafe impl Sync zu verwenden sein:

extern crate crossbeam; 

use std::cell::RefCell; 

fn main() { 
    struct Wrap(RefCell<i32>); 
    unsafe impl Sync for Wrap {}; 
    let val = Wrap(RefCell::new(1)); 

    crossbeam::scope(|scope| { 
     scope.spawn(|| *val.0.borrow()); 
    }); 
} 

Also, wie üblich mit unsafe, es ist jetzt an Ihnen zu garantieren, dass die innere RefCell in der Tat nie von mehreren zugegriffen wird Threads gleichzeitig. Soweit ich weiß, sollte dies ausreichen, um keinen Datenrennen zu verursachen.

6

Eine andere Lösung besteht darin, einen veränderbaren Verweis auf das Element in den Thread zu verschieben, obwohl keine Änderbarkeit erforderlich ist. Da es nur eine veränderbare Referenz geben kann, weiß der Compiler, dass es sicher ist, in einem anderen Thread verwendet zu werden.

extern crate crossbeam; 

use std::cell::RefCell; 

fn main() { 
    let mut val = RefCell::new(1);  
    let val2 = &mut val; 

    crossbeam::scope(|scope| { 
     scope.spawn(move || *val2.borrow()); 
    }); 
} 
+2

Dies ist zulässig, weil 'RefCell ' 'Send' implementiert. – bluss