2016-04-15 47 views
5

我有一个创建一个RefCell,然后代码要到RefCell参考传递给螺纹:如何确保不实现Sync的类型实际上可以在线程之间安全共享?

extern crate crossbeam; 

use std::cell::RefCell; 

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

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

在完整的代码,我使用的是具有嵌入RefCell类型它(一个typed_arena::Arena)。我使用crossbeam来确保线程不会超过所需的参考。

这会产生错误:

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

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

我相信我明白为什么这个错误发生:RefCell没有设计从多个线程同时调用,因为它使用内置的可变性,需要的常态机制单个可变借入不会阻止多个并发动作。这甚至在案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 .

这是在这种情况下都很好,但,我知道,只有一个线程可以访问RefCell。我如何向编译器申明我明白我在做什么,并确保这是事实?当然,如果我的推论说这实际上是安全的是不正确的,我会很乐意被告知为什么。

回答

2

当然,一种办法是使用的包装用unsafe impl Sync

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()); 
    }); 
} 

所以,像往常一样unsafe,现在是你来保证内部RefCell确实从来没有从多个访问同时线程。据我所知,这应该足以让它不会导致数据竞争。

6

另一种解决方案是将可变引用移动到该线程中,即使不需要可变性。由于只能有一个可变引用,因此编译器知道在另一个线程中使用它是安全的。

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

这是允许的,因为'RefCell '实现'发送'。 – bluss

相关问题