我的代码创建了RefCell
,然后想要将对RefCell
的引用传递给单个主题:
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
:
非
Sync
的类型是具有内部可变性的类型&#34;以非线程安全的方式,例如Cell
中的RefCell
和std::cell
。
这一切都很好,但在这种情况下 ,我知道只有一个线程能够访问RefCell
。我怎样才能向编译器确认我理解我在做什么,我确保是这样的?当然,如果我认为这实际上是安全的是不正确的,那么我很高兴被告知为什么。
答案 0 :(得分:7)
另一个解决方案是将项目的可变引用移动到线程中,即使不需要可变性。由于只能有一个可变引用,编译器知道在另一个线程中使用它是安全的。
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());
});
}
答案 1 :(得分:4)
好吧,一种方法是使用带有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
确实永远不会同时从多个线程访问。据我了解,这应该足以让它不会导致数据竞争。