我有一些多线程代码给我带来麻烦。这是我能复制的最简单的代码:
use std::thread;
use std::time;
use std::sync::{Arc, atomic::{Ordering, AtomicBool}};
use std::ops::Drop;
struct Container {
// Join Handle for a thread
th: Option<thread::JoinHandle<()>>,
// Gets set to true when we want the thread to exit
stop_thread: Arc<AtomicBool>,
}
impl Container {
fn new() -> Self {
// Create new instance
let mut inst = Self {
th: None,
stop_thread: Arc::new(AtomicBool::new(false)),
};
let stop_thread = inst.stop_thread.clone();
// Start a new thread that does some work
let t = thread::spawn(move || {
// Keep doing work until stop_thread gets set to true
while !stop_thread.load(Ordering::SeqCst) {
println!("Doing stuff...");
thread::sleep(time::Duration::from_secs(1));
}
println!("Thread exited");
});
inst.th = Some(t);
inst
}
}
impl Drop for Container {
fn drop(&mut self) {
self.stop_thread.store(true, Ordering::SeqCst);
if let Some(t) = self.th {
t.join().unwrap();
}
}
}
fn main() {
let c = Container::new();
thread::sleep(time::Duration::from_secs(3));
drop(c);
}
这个想法是,当Container
结构体的一个新实例被创建时,一个后台线程开始做一些事情。它一直运行,直到实例被销毁,此时,我需要通知线程它需要退出。我还需要在继续之前实际等待线程退出。
一切都很好,除了drop
函数中的代码。Rust对if let Some(t) = self.th
不满意。它说:
error[E0507]: cannot move out of `self.th.0` which is behind a mutable reference
--> src/main.rs:45:26
|
45 | if let Some(t) = self.th {
| - ^^^^^^^ help: consider borrowing here: `&self.th`
| |
| data moved here
| move occurs because `t` has type `JoinHandle<()>`, which does not implement the `Copy` trait
为什么我不能这样做?self.th.0
是什么?
当我尝试接受Rust的建议,并做if let Some(t) = &self.th
代替时,它仍然无法编译:
error[E0507]: cannot move out of `*t` which is behind a shared reference
--> src/main.rs:46:13
|
46 | t.join().unwrap();
| ^ move occurs because `*t` has type `JoinHandle<()>`, which does not implement the `Copy` trait
我做错了什么?
在这个答案中指定(由Rabbid76链接),这可以通过使用.take()
函数来解决:
impl Drop for Container {
fn drop(&mut self) {
self.stop_thread.store(true, Ordering::SeqCst);
if let Some(t) = self.th.take() {
t.join().unwrap();
}
}
}
尽管您可能想要考虑是否等待drop
实现中的另一个线程是一个好主意,正如这里所解释的