Rust 中的共享循环引用

2023-12-01

我正在尝试实现一个非常幼稚的线程池模型。目前线程池的职责是:

  • create一个新线程并返回对其的引用
  • 维护已创建线程的映射
  • 根据线程触发的不同事件来改变线程

我的主要问题是上面的要求迫使我让线程池保持一个HashMap<Id, Thread>线程,而且还在创建线程时提供对线程的引用。

最重要的是,我需要能够从任何线程内部调用线程池的方法,从而有效地最终改变 1 个或多个线程(调用者和目标)。

这是一个非功能性的实现:

use std::collections::HashMap;
use std::cell::RefCell;

type Id = u32;
type ThreadPoolRef = RefCell<ThreadPool>;

#[derive(Debug)]
struct ThreadPool {
    pool: HashMap<Id, RefCell<Thread>>,
    id_count: Id
}

impl ThreadPool {
    fn new() -> ThreadPool {
        ThreadPool {
            pool: HashMap::new(),
            id_count: 1
        }
    }

    fn create(&mut self) -> &RefCell<Thread> {
        let thread: RefCell<Thread> =
            RefCell::new(
                Thread::new(self.id_count, RefCell::new(self))
            );
        self.id_count = self.id_count + 1;
        self.pool.insert(self.id_count, thread);
        self.pool.get(&self.id_count).unwrap()
    }
}

#[derive(Debug, Clone)]
struct Thread {
    id: Id,
    pool: ThreadPoolRef
}

impl Thread {
    fn new(id: Id, pool: ThreadPoolRef) -> Thread {
        Thread {
            id: id,
            pool: pool
        }
    }
}

fn main() {
    let thread_pool = ThreadPool::new();
    let thread1 = thread_pool.create();
    let thread2 = thread_pool.create();
    // The final goal is to call thread1.method()
    // that mutates thread1 and calls thread_pool.method2()
    // which in turn will call thread2.method3() that will effectively
    // mutate thread 2
}

铁锈游戏

我尝试了几件事,比如使用RefCell但我开始收到很多生命周期参数丢失的错误。

这是一个精简版本,我希望它是最容易解释的。


我需要能够从任何线程内部调用线程池的方法

这就要求线程池数据是互斥机制的,比如Mutex or RwLock (RefCell不适合多线程情况,请参阅the book)。此外,每个线程必须保留对线程池数据的引用,因为线程池存储线程,这会创建一个problem。为了解决这个问题,我们可以将线程池​​数据放在一个Arc并存储一个Weak在每个线程中引用它。请注意,我们使用弱引用来避免参考周期.

这实际上最终会改变 1 个或多个线程(调用者和目标)。

这就要求线程数据采用互斥机制。要最终确定要求,请注意,由于线程池数据位于Mutex,我们无法返回对线程的引用(这需要保持线程池数据锁定),因此我们还将线程数据放入Arc.

这是使用的实现示例Mutex (操场):

use std::collections::HashMap;
use std::sync::{Arc, Weak, Mutex};

type Id = u32;

struct ThreadPool {
    inner: Arc<Mutex<ThreadPoolInner>>,
}

struct ThreadPoolInner {
    pool: HashMap<Id, Arc<Mutex<ThreadInner>>>,
    id_count: Id,
}

impl ThreadPool {
    fn new() -> ThreadPool {
        let inner = ThreadPoolInner {
            pool: HashMap::new(),
            id_count: 0,
        };
        ThreadPool { inner: Arc::new(Mutex::new(inner)) }
    }

    fn create(&self) -> Thread {
        let mut inner = self.inner.lock().unwrap();
        let thread = Thread {
            inner: Arc::new(Mutex::new(ThreadInner {
                id: inner.id_count,
                pool: Arc::downgrade(&self.inner),
            })),
        };
        inner.id_count += 1;
        let id = inner.id_count;
        inner.pool.insert(id, thread.inner.clone());
        thread
    }

    fn get(&self, id: Id) -> Option<Thread> {
        let inner = self.inner.lock().unwrap();
        inner.pool.get(&id).map(|t| Thread { inner: t.clone() })
    }

    fn some_mut_method(&self) {
        let _inner = self.inner.lock().unwrap();
        println!("something with pool");
    }
}

struct Thread {
    inner: Arc<Mutex<ThreadInner>>,
}

impl Thread {
    fn get_pool(&self) -> Option<ThreadPool> {
        let inner = self.inner.lock().unwrap();
        // pool is a weak reference, upgrate try to get an Arc from it
        inner.pool.upgrade().map(|inner| ThreadPool { inner: inner })
    }

    fn some_mut_method(&self) {
        if let Some(pool) = self.get_pool() {
            pool.some_mut_method();
            let _t2 = pool.get(2).unwrap();
            println!("something with t2");
        }
    }
}

#[derive(Clone)]
struct ThreadInner {
    id: Id,
    pool: Weak<Mutex<ThreadPoolInner>>,
}

fn main() {
    let pool = ThreadPool::new();
    let t1 = pool.create();
    let _t2 = pool.create();
    t1.some_mut_method();
}
本文内容由网友自发贡献,版权归原作者所有,本站不承担相应法律责任。如您发现有涉嫌抄袭侵权的内容,请联系:hwhale#tublm.com(使用前将#替换为@)

Rust 中的共享循环引用 的相关文章

随机推荐

  • 构建 Logistic 回归模型时出现“检测到完美分离,结果不可用”

    作为我作业的一部分 我正在构建逻辑回归模型 但在构建模型时出现错误 检测到完美分离 结果不可用 X train year amt spnt rank 1 1 723034 0 418500 0 272727 2 0 716660 2 088
  • QTimer::timeout 没有触发

    我正在尝试创建一个在我的 Singleton 工作线程中每 n 秒触发一次的事件 信号 槽连接 信号是 QTimer 超时 槽是调用另一个 Singleton 类的 lambda 函数 无法正常工作 连接调用成功 计时器处于活动状态 并且我
  • 两列布局,左侧流体,右侧填充其余宽度

    我需要类似的东西this and this 但是我希望右列不是固定大小 而是可变大小 是否可以 some text stretch to fill the remaining space lt viewport 这是float解决方案 您可
  • Java 构造函数中的“this”

    嗯 这是一个非常基本的问题 我从来没有用java编写过代码 但我正在为朋友编写一个类 有类似的东西 class myClass private string name public string getName return this na
  • 如何通过php找到给定的十进制值的位数?

    我对php不太熟悉 但我知道我们可以通过php找到给定数字的位值 例如 如果输入为 23 56 则应回显 2 十 3 个 5 百分之一 6 千分之一 任何想法将不胜感激 请帮忙 Try str 23 56 strdiv explode st
  • Spark RDD:如何最有效地计算统计数据?

    假设存在类似于以下的元组 RDD key1 1 key3 9 key2 3 key1 4 key1 5 key3 2 key2 7 计算每个键对应的统计信息的最有效 并且理想情况下是分布式 的方法是什么 目前 我特别希望计算标准差 方差 据
  • 二维数组与一维数组的性能

    在 C 中 m n 二维数组与长度为 m n 的一维数组 对于 m 和 n 的较大值 之间在时间和空间上是否存在差异 使用一维数组访问元素会更快吗 在 C 中 二维数组只是一维数组的简洁索引方案 就像一维数组一样 二维数组分配单个连续内存块
  • 无法在 webview 上加载地理位置

    我想将地理位置加载到 android 2 1 上的 webview 中 地理定位在我的浏览器上运行良好 但在 webview 上却失败了 public class WebPageLoader extends Activity impleme
  • Pyspark:pandas_udf、grouped_agg 的多个参数

    我正在尝试应用带有两个参数的 pandas udf 但我有这个错误 首先我尝试使用一个参数 没问题 from pyspark sql functions import pandas udf PandasUDFType from pyspar
  • re.sub 中的 python 正则表达式条件 - 如何?

    是否可以使用python的正则表达式条件re sub 我尝试了多种变体但没有运气 这就是我所拥有的 import re match anything
  • Spring - 自动装配通用接口的通用实现

    我有一个小问题 这可能是微不足道的 但我以前从未遇到过 我有通用接口和它的通用实现 我想自动装配它 但发生了错误 详细信息如下 界面 Service public interface Serializing
  • Node-Webkit (nwjs) 节点远程用法

    我想知道如果我想从服务器运行应用程序的一些逻辑 功能 是否有人可以给我一个关于 节点远程 如何工作的示例 就像 我不知道在 package json 添加 node remote hostip 后该怎么做 我的服务器应该提供什么 js 文件
  • Scala:确保大括号平衡

    我正在运行代码来平衡语句中的括号 我认为我已经得到了正确的结果 但它在一个特定的陈述上失败了 我需要理解为什么 这是测试 特别是它失败了 除了编码之外 我认为我需要修复算法 有什么指示吗 def balance chars List Cha
  • 将“Cookie”放入“CookieJar”中

    我正在使用PythonRequests库来发出 HTTP 请求 我从服务器获取文本形式的 cookie 我怎样才能把它变成CookieJar里面有饼干吗 旧版本的Requests图书馆 0 14 2和更老的 当你经过时 把新的饼干放进罐子里
  • 如何使用 Jquery 或 Javascript 更改 .CSS 文件?

    我想知道是否可以使用 Jquery 或 javascript 对 css 文件进行更改 我知道 我可以动态地将 css 属性 或类 添加到 DOM 元素 但我不想要那样 我想在 css 文件中进行更改以自定义 css 文件的 css 类 请
  • 如何为 EF Code First 配置 ProviderManifestToken

    我有一个使用 EF 代码优先的 asp net MVC3 项目 对于我的单元测试 我一直使用 SQL Server CE 4 0 和 SQL Server 2008 Express 两者都与 EF 完美配合 按预期生成我的数据库 但是 当我
  • Jackson Scala JSON 反序列化为案例类

    我有一个 JSON 其形式如下 inventory productType someProduct1 details productId Some id description some description productType so
  • 如何在 Puppeteer page.$eval 中传递函数/变量? [复制]

    这个问题在这里已经有答案了 我正在使用 Puppeteer 自动填写网络表单 每次 input 字段中的名称都应更改为数组中的不同名称 如果我直接在 page eval 函数中指定一个名称 例如 Michael 一切都会按预期工作 pupp
  • 删除序列化程序创建的空 xmlns

    我有一个由 添加服务引用 操作生成的对象 并且我使用我编写的通用序列化器手动序列化它 我的问题是数据契约有一些内部对象 序列化程序将一个空的命名空间属性添加到内部对象的起始标记中 有什么办法可以阻止这种情况发生吗 让你的内部对象与根属于同一
  • Rust 中的共享循环引用

    我正在尝试实现一个非常幼稚的线程池模型 目前线程池的职责是 create一个新线程并返回对其的引用 维护已创建线程的映射 根据线程触发的不同事件来改变线程 我的主要问题是上面的要求迫使我让线程池保持一个HashMap