如何冻结Rc数据结构并跨线程发送它

问题描述

我的应用程序分两个阶段工作:

  1. 创建了一个大型数据结构,其中涉及大量临时对象,并使用引用计数进行堆管理
  2. 将数据结构设置为只读,将所有仍在运行的数据停放,并将结果结构发送到另一个线程进行读取。

(为了更加具体,该应用程序是语言服务器,并且数据结构是处理的单个文件,这些文件是单线程处理的,但其结果必须跨线程传递。)

当前,我正在使用Arc<T>来管理数据结构,但是由于阶段1既庞大又昂贵,并且是单线程的,所以我想将其切换为使用Rc<T>。但是Rc既不是Send也不是Sync,这是有充分的理由的,除非程序中基本上所有内容都使用线程安全的原语,否则我将无法发送数据结构或对其的引用。 / p>

我想说第二阶段开始后,我们不再需要引用计数了。线程1(所有者)不允许触摸引用计数,线程2(借款人)不允许克隆数据,只能查看数据,因此也不能触摸引用计数。我知道Rc不会提供这组保证,因为您可以克隆给定共享引用的Rc。此模式是否有安全的API?理想情况下,从阶段1到阶段2时,我不必复制任何数据。

这是一个玩具实现,只是在其中添加了一些代码。函数phase1()在返回类型为T的数据结构之前会产生大量垃圾,然后在另一线程上的phase2()中以只读方式对其进行分析。如果您在此代码中将Arc更改为Rc,则会收到错误消息,因为它无法跨线程发送。

use std::sync::Arc;
use crossbeam::thread::scope; // uses the crossbeam crate for scoped threads

enum T { Nil,More(Arc<T>) }

fn phase1() -> T {
    let mut r = T::Nil;
    for i in 0..=5000 {
        r = T::Nil;
        for _ in 0..i { r = T::More(Arc::new(r)) }
    }
    r
}

fn phase2(mut t: &T) {
    let mut n = 0;
    while let T::More(a) = t {
        n += 1;
        t = a;
    }
    println!("length = {}",n); // should return length = 5000
}

fn main() {
    let r = phase1();
    scope(|s| { s.spawn(|_| phase2(&r)); }).unwrap();
}

解决方法

暂无找到可以解决该程序问题的有效方法,小编努力寻找整理中!

如果你已经找到好的解决方法,欢迎将解决方案带上本链接一起发送给小编。

小编邮箱:dio#foxmail.com (将#修改为@)