如何保证未实现 Sync 的类型实际上可以在线程之间安全地共享? [英] How can I guarantee that a type that doesn't implement Sync can actually be safely shared between threads?

查看:57
本文介绍了如何保证未实现 Sync 的类型实际上可以在线程之间安全地共享?的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

我有创建 RefCell 的代码,然后想将对该 RefCell 的引用传递给 单个 线程:

I have code that creates a RefCell and then wants to pass a reference to that RefCell to a single thread:

use crossbeam; // 0.7.3
use std::cell::RefCell;

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

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

在完整的代码中,我使用了一种嵌入了 RefCell 的类型(a typed_arena::Arena).我正在使用 crossbeam 来确保线程不会超过它所需要的引用.

In the complete code, I'm using a type that has a RefCell embedded in it (a typed_arena::Arena). I'm using crossbeam to ensure that the thread does not outlive the reference it takes.

这会产生错误:

error[E0277]: `std::cell::RefCell<i32>` cannot be shared between threads safely
 --> src/main.rs:8:15
  |
8 |         scope.spawn(|_| *val.borrow());
  |               ^^^^^ `std::cell::RefCell<i32>` cannot be shared between threads safely
  |
  = help: the trait `std::marker::Sync` is not implemented for `std::cell::RefCell<i32>`
  = note: required because of the requirements on the impl of `std::marker::Send` for `&std::cell::RefCell<i32>`
  = note: required because it appears within the type `[closure@src/main.rs:8:21: 8:38 val:&std::cell::RefCell<i32>]`

我相信我明白为什么会发生这个错误:RefCell 不是为从多个线程并发调用而设计的,并且由于它使用内部可变性,需要单个可变借用的正常机制不会防止多个并发操作.这甚至记录在 Sync:

I believe I understand why this error happens: RefCell is not designed to be called concurrently from multiple threads, and since it uses internal mutability, the normal mechanism of requiring a single mutable borrow won't prevent multiple concurrent actions. This is even documented on Sync:

不是 Sync 的类型是那些在非线程安全形式中具有内部可变性"的类型,例如 cell::Cellcell::RefCell.

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

这一切都很好,但是在这种情况下,我知道只有一个线程能够访问 RefCell.我如何向编译器确​​认我理解我在做什么并且我确保是这种情况?当然,如果我认为这实际上是安全的推理是不正确的,我很乐意被告知原因.

This is all well and good, but in this case, I know that only one thread is able to access the RefCell. How can I affirm to the compiler that I understand what I am doing and I ensure this is the case? Of course, if my reasoning that this is actually safe is incorrect, I'd be more than happy to be told why.

推荐答案

一种方法是使用带有 unsafe impl Sync 的包装器:

One way would be to use a wrapper with an unsafe impl Sync:

use crossbeam; // 0.7.3
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());
    })
    .unwrap();
}

和通常的 unsafe 一样,现在由您来保证内部 RefCell 确实不会同时被多个线程访问.据我了解,这应该足以避免导致数据竞争.

As usual with unsafe, it is now up to you to guarantee that the inner RefCell is indeed never accessed from multiple threads simultaneously. As far as I understand, this should be enough for it not to cause a data race.

这篇关于如何保证未实现 Sync 的类型实际上可以在线程之间安全地共享?的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆