为什么这个Rust代码等待线程完成不工作?



我有一些多线程代码给我带来麻烦。这是我能复制的最简单的代码:

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实现中的另一个线程是一个好主意,正如这里所解释的

最新更新