如果strong_count为1,weak_count为0,发送包含Rc的结构是否安全?

问题描述 投票:2回答:1

我有一个不是Send的结构,因为它包含Rc。可以说Arc的开销太大,所以我想继续使用Rc。我仍然偶尔希望在线程之间使用此结构Send,但仅当我可以验证Rc的强度为1且强度为0时才可以。

我想到的是(希望很安全)抽象:

mod my_struct {
    use std::rc::Rc;

    #[derive(Debug)]
    pub struct MyStruct {
        reference_counted: Rc<String>,
        // more fields...
    }

    impl MyStruct {
        pub fn new() -> Self {
            MyStruct {
                reference_counted: Rc::new("test".to_string())
            }
        }

        pub fn pack_for_sending(self) -> Result<Sendable, Self> {
            if Rc::strong_count(&self.reference_counted) == 1 &&
               Rc::weak_count(&self.reference_counted) == 0
            {
                Ok(Sendable(self))
            } else {
                Err(self)
            }
        }

        // There are more methods, some may clone the `Rc`!
    }

    /// `Send`able wrapper for `MyStruct` that does not allow you to access it,
    /// only unpack it.
    pub struct Sendable(MyStruct);

    // Safety: `MyStruct` is not `Send` because of `Rc`. `Sendable` can be
    //         only created when the `Rc` has strong count 1 and weak count 0.
    unsafe impl Send for Sendable {}

    impl Sendable {
        /// Retrieve the inner `MyStruct`, making it not-sendable again.
        pub fn unpack(self) -> MyStruct {
            self.0
        }
    }
}

use crate::my_struct::MyStruct;

fn main() {
    let handle = std::thread::spawn(|| {
        let my_struct = MyStruct::new();
        dbg!(&my_struct);

        // Do something with `my_struct`, but at the end the inner `Rc` should
        // not be shared with anybody.

        my_struct.pack_for_sending().expect("Some Rc was still shared!")
    });

    let my_struct = handle.join().unwrap().unpack();
    dbg!(&my_struct);
}

我在Rust playground上进行了演示。

有效。我的问题是,实际上安全吗?

[我知道Rc仅由一个拥有者拥有,没有人可以在我的手上进行更改,因为其他线程无法访问它,因此我们将其包装到Sendable中,该C0不允许访问包含价值。

但是在某个疯狂的世界中,Rc例如可以在内部使用线程本地存储,因此这并不安全...因此,可以保证我可以做到这一点吗?

我知道我必须非常小心,不要引入某些其他原因使MyStruct不是Send

rust unsafe
1个回答
0
投票

ArcRc之间的唯一区别是Arc使用原子计数器。仅在克隆或删除指针时才访问计数器,因此在仅在长寿命线程之间共享指针的应用程序中,两者之间的差异可以忽略不计。

如果您从未克隆过Rc,则在线程之间发送是安全的。但是,如果可以guarantee指针是唯一的,那么就可以对原始值进行相同的保证,而无需使用任何智能指针!

这一切似乎都很脆弱,没有什么好处;将来对代码的更改可能不符合您的假设,并且您最终将获得未定义的行为。我建议您至少尝试使用Arc进行一些基准测试。仅在评估性能问题时才考虑采用这种方法。


您还可以考虑使用archery crate,它提供了一个引用计数的指针,该指针抽象了原子性。

© www.soinside.com 2019 - 2024. All rights reserved.