I want to create a thread inside of the new
method and stop it after the struct is destroyed:
use std::thread;
struct Foo {
handle: thread::JoinHandle<()>,
}
impl Foo {
pub fn new(name: &str) -> Foo {
let name = name.to_string();
Foo {
handle: thread::spawn(move || {
println!("hi {}", name);
}),
}
}
pub fn stop(&mut self) {
self.handle.join();
}
}
fn main() {
let mut foo = Foo::new("test");
foo.stop();
}
This doesn't compile, and I can not understand why:
error[E0507]: cannot move out of borrowed content
--> <anon>:15:9
|
15 | self.handle.join();
| ^^^^ cannot move out of borrowed content
And in newer versions of Rust:
error[E0507]: cannot move out of `self.handle` which is behind a mutable reference
--> src/main.rs:17:9
|
17 | self.handle.join();
| ^^^^^^^^^^^ move occurs because `self.handle` has type `std::thread::JoinHandle<()>`, which does not implement the `Copy` trait
How can I fix this error?
In the future, I will implement Drop
for Foo
, and will call stop()
from drop()
.
What is a Join Method in Java? Join method in Java allows one thread to wait until another thread completes its execution. In simpler words, it means it waits for the other thread to die. It has a void type and throws InterruptedException.
The wait() is used for inter-thread communication while the join() is used for adding sequencing between multiple threads, one thread starts execution after first thread execution finished.
Wait() method releases lock during Synchronization. Sleep() method does not release the lock on object during Synchronization. Wait() should be called only from Synchronized context. There is no need to call sleep() from Synchronized context.
join() a ThreadTo tell one thread to wait for another thread to finish, you call . join() . If you uncomment that line, the main thread will pause and wait for the thread x to complete running.
The function signature of JoinHandle::join
is:
fn join(self) -> Result<T>
This means that the method takes self
(the receiver object) by values (taking the ownership/consuming it). But you only have a borrow to your JoinHandle
; a mutable one, but still merely a borrow, not the ownership. Thus you can't call this method, because you can't move the ownership out of your borrow into this join()
method.
An easy way to fix that, is by accepting self
by value in the stop()
method, too:
pub fn stop(self) {
self.handle.join();
}
But you will notice that this isn't possible when implementing Drop
, because drop()
has the signature fn drop(&mut self)
! Bummer! But there is a little trick you can use, described below. Please be aware that joining threads in drop()
is probably not a good idea! Read Matthieu M.'s answer for more information on that!
If you still think, for whatever reason, that you really want to join a thread in drop()
, you can store the JoinHandle
in an Option<T>
to save whether or not it's already joined. If you have a Some(T)
you can obtain a T
(by value!) from it by using the method Option::take()
. Then you can write:
fn drop(&mut self) {
// `self.handle` has the type `Option<JoinHandle<()>>` here!
if let Some(handle) = self.handle.take() {
handle.join().expect("failed to join thread");
}
}
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With