首页 > 解决方案 > 引用 Mutex 内部的数据

问题描述

我想访问受 RwLock 保护的数据。不幸的是,我被迫返回参考。

背景:我将rust-qt-binding-generator与 QtQuick 一起使用,我想可视化在 rust 端异步接收的数据。数据以 Vec 的形式出现,因此,我想在 Qt 端使用 QByteArray。rust-qt-binding-generator 提供了这种数据类型。

我的问题是生成的特征需要具有以下签名的 getter 函数:

fn channels(&self) -> &[u8]

代码:

#![allow(unused_imports)]
#![allow(unused_variables)]
#![allow(dead_code)]
use interface::*;
use std::sync::{Arc, RwLock, RwLockWriteGuard};
use std::time::Duration;
use std::thread;

pub struct RustController {
    emit: RustControllerEmitter,
    ch_vals: Vec<u8>,
    channels: Arc<RwLock<Vec<u8>>>
}

impl RustControllerTrait for RustController {
    fn new(emit: RustControllerEmitter) -> RustController {
        let mut ret = RustController {
            emit: emit.clone(),
            ch_vals: vec!(),
            channels: Arc::new(RwLock::new(create_empty_vector())),
        };

        update_thread(emit, ret.channels.clone());
        ret
    }
    fn emit(&self) -> &RustControllerEmitter {
        &self.emit
    }
    fn channels(&self) -> &[u8] {
        // *((*self.channels).read().unwrap()).clone()
        // does not work of course (and nothing else I tried obviously)
        // because I can only get the value as a temporary one. writing
        // them into self.ch_vals would solve the problem, but I am not
        // allowed to get a &mut self

        //&self.ch_vals     // <-- this would work, but does not contain
                            //     the values generated in the thread.
    }
}

fn create_empty_vector() -> Vec<u8> {
    let mut ret: Vec<u8> = Vec::with_capacity(512);

    for i in 0..512 {
        ret.push((i/2) as u8);
    }

    ret
}

fn update_thread(
    emit: RustControllerEmitter,
    channels: Arc<RwLock<Vec<u8>>>,
) {
    thread::spawn(move || {
        loop {
            {
                let mut w: RwLockWriteGuard<Vec<u8>> = (*channels).write().unwrap();
                (*w)[0] += 1;
                // changing values in the mutex is no problem, but no
                // reference to the RustController here to store value
            }

            emit.channels_changed();
            thread::sleep(Duration::from_secs(1));
        }
    });
}

如果你想自己运行它,这里是我的 bindings.json:

{
    "cppFile": "src/Bindings.cpp",
    "rust": {
        "dir": "rust",
        "interfaceModule": "interface",
        "implementationModule": "implementation"
    },
    "objects": {
        "RustController": {
            "type": "Object",
            "properties": {
                "channels": {
                    "type": "QByteArray"
                }
            }
        }
    }
}

使用此设置,我可以毫无问题地传输 i32,但 Vec 由于吸气剂而无法工作。我对这个问题的理解是,我无法将额外线程中生成的值存储在可以在 getter 中引用的位置(并且寿命足够长,理想情况下只要使用 RustController)。

标签: multithreadingrustmutex

解决方案


推荐阅读