我有一个多线程程序,它想要跨线程访问资源。一些想要写到它们,一些想要从它们读取。
我不确定这是否算作a global mutable singleton,因为我的设置不是全局的,但解决方案可能是类似的?
下面的代码是一个非常简化的版本。
它试图做的是,让一个线程写入一个结构体,另一个线程从同一个结构体读取。因此,当线程A变异数据时,线程B将读取变异的数据。
use std::{thread, time::Duration};
struct TagList {
list: Vec<String>
}
impl TagList {
fn add(self: &mut TagList, tag: String) {
self.list.push(tag);
}
fn read(&self) -> Vec<String> {
self.list.clone()
}
}
fn main() {
let mut list = TagList { list: vec![] };
thread::spawn(move || {
["fee", "foo", "faa", "fuu"].into_iter().for_each(|tag| {
list.add(tag.to_string());
thread::sleep(Duration::from_millis(100));
});
});
thread::spawn(move || {
loop {
dbg!(list.read());
thread::sleep(Duration::from_millis(20));
}
});
}
很明显,这会因借位错误而失败:
error[E0382]: use of moved value: `list`
--> src/main.rs:79:19
|
70 | let mut list = TagList { list: vec![] };
| -------- move occurs because `list` has type `TagList`, which does not implement the `Copy` trait
71 |
72 | thread::spawn(move || {
| ------- value moved into closure here
73 | ["fee", "foo", "faa", "fuu"].into_iter().for_each(|tag| {
74 | list.add(tag.to_string());
| ---- variable moved due to use in closure
...
79 | thread::spawn(move || {
| ^^^^^^^ value used here after move
80 | dbg!(list.read());
| ---- use occurs due to use in closure
我已经尝试通过将列表 Package 在Arc
中来解决这个问题:
use std::sync::Arc;
// ...
let list = Arc::new(TagList { list: vec![] });
let write_list = Arc::get_mut(&mut list).unwrap();
let read_list = Arc::clone(&list);
thread::spawn(move || {
["fee", "foo", "faa", "fuu"].into_iter().for_each(|tag| {
write_list.add(tag.to_string());
thread::sleep(Duration::from_millis(100));
});
});
thread::spawn(move || {
loop {
dbg!(read_list.read());
thread::sleep(Duration::from_millis(20));
}
});
这失败了,因为我可能不理解Arc应该如何工作,或者它与生命周期的关系:
error[E0597]: `list` does not live long enough
--> src/main.rs:71:35
|
71 | let write_list = Arc::get_mut(&mut list).unwrap();
| -------------^^^^^^^^^-
| | |
| | borrowed value does not live long enough
| argument requires that `list` is borrowed for `'static`
...
85 | }
| - `list` dropped here while still borrowed
error[E0502]: cannot borrow `list` as immutable because it is also borrowed as mutable
--> src/main.rs:72:32
|
71 | let write_list = Arc::get_mut(&mut list).unwrap();
| -----------------------
| | |
| | mutable borrow occurs here
| argument requires that `list` is borrowed for `'static`
72 | let read_list = Arc::clone(&list);
| ^^^^^ immutable borrow occurs here
我想要的东西是可能的吗?(我很确定我已经看到了它的使用,例如std::sync::mpsc
,其中消息以某种方式通过线程被推和读取)。我应该使用什么?Arc
是正确的结构吗?还是我在那里看到了错误的解决方案?我应该阅读什么来理解这些问题通常是如何在Rust中解决的?
1条答案
按热度按时间p5fdfcr11#
Arc
不允许突变,并且Arc::get_mut()
不是该问题的解决方案。当Arc
只有一个示例时(因此出现第二个错误),它允许突变,并且返回一个不是'static
的引用,因此您无法将其移动到线程中(第一个错误)。如果您需要改变
Arc
的内容,请使用Mutex
或RwLock
。