可以`Send`的替代`RefCell`?

5
我正在设计一个类型,该类型可以根据是否为 Owned 类型来确定能否在不同线程之间发送。
这段代码:
use std::cell::RefCell;
use std::rc::Rc;

pub enum M<'a, T> {
    Owned(),
    Ref(Rc<RefCell<&'a mut [T]>>)
}

fn main() {
    let m: M<'static, u8> = M::Owned();
    std::thread::spawn(||{
        let m = m;
    });
}

提供

error[E0277]: `Rc<RefCell<&mut [_]>>` cannot be sent between threads safely
   --> src/main.rs:11:5
    |
11  |       std::thread::spawn(||{
    |  _____^^^^^^^^^^^^^^^^^^_-
    | |     |
    | |     `Rc<RefCell<&mut [_]>>` cannot be sent between threads safely
12  | |         let m = m;
13  | |     });
    | |_____- within this `[closure@src/main.rs:11:24: 13:6]`

我理解这不是发送(Send),因为RefCell!Send。我认为这是妨碍M成为发送(Send)的唯一原因。是否有一个RefCell的替代品可以发送(Send)


这不是与几分钟前提出的 https://stackoverflow.com/q/68241072/5987669 相同的问题吗? - Locke
1
你可以随意共享 Arc<Mutex<T>>。然而,拥有这个结构似乎会带来更多的问题,不值得。那个生命周期可能会在未来给你带来麻烦。Playground 链接 - Locke
@Locke 我只希望发送这个结构体的“静态”版本。在每个将其发送到另一个线程的代码中,它已经期望 M 是“静态”的。然而,我仍然希望支持一些情况,其中它保留了引用,以便可以在同一线程上完成一些操作。 - Guerlando OCs
1个回答

4
我知道这不是Send,因为RefCell不是Send。我认为这是阻止M成为Send的唯一原因。
是的,这是正确的。
当然,至少有两个RefCell替代品是可以Send的。如果你只想在另一个线程中使用&mut,你实际上可以直接发送它:
#[derive(Debug)]
pub enum M<'a, T> {
    Owned(),
    Ref(&'a mut [T])
}

fn main() {
    let m: M<'static, u8> = M::Owned();
    std::thread::spawn(move ||{
        println!("{:?}", m);
    }).join().unwrap();
}

但是如果您使用 Rc<RefCell<_>>,例如使您的 &mut 可共享,您可以通过 Arc<Mutex<_>> 在多线程上下文中实现相同的功能,正如 @Locke 已经提到的:

use std::sync::{Arc, Mutex};

#[derive(Debug, Clone)]
pub enum M<'a, T> {
    Owned(),
    Ref(Arc<Mutex<&'a mut [T]>>)
}

fn main() {
    let m: M<'static, u8> = M::Owned();
    let m2 = m.clone();
    std::thread::spawn(move ||{
        println!("{:?}", m2);
    }).join().unwrap();
    println!("{:?}", m);
}

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接