rust - 数据互斥带来的 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();
}
}
在操场上看到错误
解决方案
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);
// ^^^^^^^^
这是一个完整的例子。不需要生命周期参数。
一般来说,您应该避免将引用放在结构中,因为只有在编译时非常努力地证明生命周期关系时才能安全地完成它。在大多数情况下,您应该简单地克隆数据,或者如果这是错误的语义,请使用Arc
or Rc
。mpsc::Sender
内部使用Arc
便宜克隆。