首页 > 解决方案 > 数据互斥带来的 Rust 生命周期问题

问题描述

我已经尽可能地缩小了这个范围。我有一个引用向量,Senders并希望在receive()完成运行后处理它们。但是,我遇到了终身管理问题。内部结构Mutex受保护并包含Senders我试图引用的结构。我使用 Mutex 来获得数据的可变性,我对替代方案持开放态度。关于如何解决这个问题的任何建议?我不想更改receive() 的签名。

use std::sync::Mutex;
use std::sync::mpsc;

#[derive(Default)]
struct SaveForLater<'a> {
    queue: Vec<(&'a mpsc::Sender<usize>, usize)>,
}
impl<'a> SaveForLater<'a> {
    fn send(&mut self, channel: &'a mpsc::Sender<usize>, value: usize) {
        self.queue.push((channel, value));
    }
}

#[derive(Default)]
struct Forwarder {
    data: Mutex<ForwarderData>,
}
#[derive(Default)]
struct ForwarderData {
    senders: Vec<mpsc::Sender<usize>>,
}

impl Forwarder {
    fn with_capacity(capacity: usize) -> Self {
        let mut senders = Vec::new();
        for _ in 0..capacity {
            let (s,r) = mpsc::channel();
            senders.push(s);
        }
        let data = ForwarderData { senders };
        let data = Mutex::new(data);
        Self { data }
    }

    fn receive<'a>(&'a self, value: usize, sender: &mut SaveForLater<'a>) {
        match value {
            0 => { self.data.lock().unwrap().senders.drain(..); },
            _ => {
                let data = self.data.lock().unwrap();
                sender.send(&data.senders[0], value); },
/*
error[E0597]: `data` does not live long enough
  --> src/main.rs:40:30
   |
35 |     fn receive<'a>(&'a self, value: usize, sender: &mut SaveForLater<'a>) {
   |                -- lifetime `'a` defined here
...
40 |                 sender.send(&data.senders[0], value); },
   |                 -------------^^^^-------------------  - `data` dropped here while still borrowed
   |                 |            |
   |                 |            borrowed value does not live long enough
   |                 argument requires that `data` is borrowed for `'a`
*/
        }
    }
}

fn main() {
    let fwd = Forwarder::with_capacity(3);
    {
        let mut sender = SaveForLater::default();
        let value: usize = 42;
        fwd.receive(value, &mut sender);
        for (s,v) in sender.queue {
            s.send(v);
        }   
    }
}

#[cfg(test)]
mod tests {
    use super::*;

    #[test]
    fn test_main() {
        main();
    }
}

在操场上看到错误

标签: rust

解决方案


Mutex在这里是一种干扰;真正的问题是试图将引用存储在结构中。让我们看一下文档,mpsc::Sender看看它应该如何使用:

Rust 异步channel类型的发送部分。这一半只能由一个线程拥有,但可以克隆以发送给其他线程。

Sender甚至没有实现Sync,所以即使你让借用检查器高兴,你也不能在多个线程之间共享一个。它应该被克隆

struct SaveForLater {
    queue: Vec<(mpsc::Sender<usize>, usize)>,
}
    fn receive(&self, value: usize, sender: &mut SaveForLater) {
        // ...
                sender.send(data.senders[0].clone(), value);
                //                         ^^^^^^^^

这是一个完整的例子。不需要生命周期参数。

一般来说,您应该避免将引用放在结构中,因为只有在编译时非常努力地证明生命周期关系时才能安全地完成它。在大多数情况下,您应该简单地克隆数据,或者如果这是错误的语义,请使用Arcor Rcmpsc::Sender内部使用Arc便宜克隆。


推荐阅读