- When you spawn a thread
the spawn function returns a thread handle.
The handle is of type join handle, that's the structure.
And the join handle structure has a join method.
When you call join
your main thread waits
for the other thread to finish.
If the thread is already finished
then it returns immediately
and then you proceed.
So the idea is the main thread,
you kick off a background thread
the main thread does some work
and then the main thread says join
or wait for that other thread to finish.
I'm gonna wait for that other thread to finish
and then I can continue doing some other work afterwards.
So here's a simple example,
I call the thread function.
The thread spawn function returns a joint handle
and then on the joint handle I call the join method.
Now the joint method returns a result
you know the Rust result Enum type.
All right and that basically indicates
how did that other thread finish?
The result could be OK
which means the other thread terminated successfully.
No problem here.
Or the result that you get back
could be an Err
which means the other thread panicked.
It basically failed.
So you have to be a bit careful
if you call handle.join
and the result that you get back,
if you just call unwrap like I've shown here,
what would happen
if the result that you get back was an error?
In that case, you are gonna panic.
Your main thread will also panic.
In other words, your main thread will terminate.
Okay so you have to be a bit careful
just taking the result that this joint method returns
and then unwrap in the result Enum directly
will cause your application
or your thread to fail
if the result
that you got back from the other thread was an error.
A more careful approach
would be to do pattern matching like this, okay?
So you take the handle from the other thread
and you call join,
which basically means wait for that other thread to finish.
It could finish successfully
or it could finish by you know, failing.
So test the result that comes back from the join method
and if the result is OK,
it means I don't care about the value,
I just wanna know that it was OK.
In that case it indicates that the join result is OK
it means that the other thread terminated successfully.
Or if the result that you get back here is an error
then we can print a message
to say the join result is an error.
It means that the other thread failed it.
What it actually means in practice
is that the other thread panicked
it terminated abnormally
and we can get back the result here
and we can decide what to do
if that other thread failed.
So we're gonna run some different scenarios
in our demo code.
I'll start off with main obviously,
and then the the code we're gonna run
it's going to be demo join in thread single
which kind of suggests
that there might later be another demo
about how to join multiple threads.
Watch this space,
that's coming up later on.
Okay, so let's have, look at the code.
Well here we are in the main code.
I'm gonna un-comment the demo for this part.
Demo join in single thread basically,
and it is here, right?
So let me run you through the code for the scenario.
Here is the code that I want to run in a separate thread.
Okay, so I spawn a closure
and that closure is quite simple.
It just prints out the message
to say the background thread
whatever its ideas is starting
waits quite a long time,
it waits 10 seconds.
So there's not a lot going on.
Obviously in reality you'd be doing some real work here
like calling a REST service,
connecting to some database,
doing some complex algorithmic calculations,
something worthwhile.
After that 10 seconds we wake up
and we say this is the end of the background thread.
Later on in about two minutes
I'm going to un-comment this code
and that will indicate
that this thread has actually terminated abnormally.
Okay so come back to un-comment that code in a moment
but as it stands currently
and the closure will get spawned
and well after 10 seconds,
it will complete successfully.
As we know when you call the spawn method
the main thread returns immediately with a handle.
A handle onto that background thread.
So the main thread continuous processing immediately
and the main thread is gonna be busy writing a loop.
So it's gonna loop round
and is that five times or six times?
Six times, isn't it?
It'll print out the main threads' ID
and it's got quite a short delay.
It's gonna loop round basically every half a second, okay?
So the main thread is gonna spin around quite quickly.
That's gonna finish quite quickly.
That's gonna finish after three seconds I think,
whilst this main thread
or this background thread I should say
it's gonna take 10 seconds to complete.
So that's still running
while the main thread finishes that bit of code
and says, well I've done all the work
that I needed to do
now I just need to wait for that other thread to finish.
So I'm not gonna wait for the other thread to end.
Okay, so the main thread is now wait then
and this is how you do it.
Well this is one way to do it.
You can say handle.join.unwrap.
Be careful because what you're assuming there
is that the the other thread
represented by the handle,
the result that you get back is OK, all right?
Well it is OK actually,
our background thread isn't gonna terminate
so you know it's not gonna terminate abnormally I mean,
so after the ten second delay is finished
that should succeed and our application should terminate.
So that's the kind of happy day scenario.
So we'll run the application like this
first of all,
cargo run.
So it's gonna take about 10 seconds
for this application to finish.
There we go.
So the main thread started printed its numbers
101 through the 106
and it completed, 105, sorry quite quickly.
The background thread started there
and then 10 seconds later it finished
and our application was waiting for it to finish
and then we terminate.
So that's fine.
'Course what I could have done,
instead of calling the unwrap function like this
I could have been a little bit more cautious
and I could have had a match statement.
So in this case,
wait for that other thread to finish
it will finish one way or the other.
And then after it's finished,
the result that we get back from the join function
we can see whether the background thread finished normally
in which case join result is OK
or and that's what we are gonna get
because the background thread, you know
there isn't anything dodgy here,
it will terminate normally.
So when we wait for it to finish,
when it has finished
we will eventually get back the result
that says, okay the joint result is OK.
And that's what we're gonna see here.
We're gonna run the application again now
using my more cautious approach to waiting
for the other thread to finish.
So I'm now waiting for the other thread to finish.
You can see the message down here
and then a few seconds later
it will finish the result then comes back,
we test it
and we realize that it says it was OK.
So in that case it says the joint result is OK
thank you for the confirmation.
I knew that was actually gonna happen.
That's all folks.
And that's the end of the demo.
Right so what we need to look at now
is what happens if the main thread panics.
In other words, if the main thread crashes.
So this is, I mean it can happen
threads can go bad, you know, bad things can happen.
So it could well be the case
especially if this thread
is doing some kind of networking
or low level systems related processing.
It could panic.
I've actually caused it to panic deliberately here.
I think this might be the first time
I've shown you the panic macro.
There's a panic macro in Rust
which deliberately causes the thread to terminate, okay?
It's like saying system.exit in other languages.
So this will cause the background thread
which had been kind of waiting for 10 seconds to finish
and then after 10 seconds
that background thread terminates with an error, right?
So that's interesting
because our main thread was waiting for it to terminate
and when it terminates with an error
the result being an error.
We've catered for that quite elegantly
and cautiously to say,
right, it did fail
but at least it didn't pull me down with it.
So we should see this message being displayed now
when we run the application.
So let's run it again
and see this cautious approach
to waiting for the other thread.
It could work, it could fail.
I'd recommend this approach
because then you know what the status was
and you maybe respond to it carefully.
So this thread did panic, okay?
We can't help that.
So we can see that that thread there panicked
with the error message.
Like my error message deliberately panicking dude,
I used to work with a guy everybody was called dude,
it's a funny bloke.
Funny, haha.
So anyway
that's where the background thread terminated, right?
My main thread was waiting for it to terminate
and it realizes in a graceful kind of way
that join result as an error.
Okay so my main thread kind of,
it's like catching an exception
would be the equivalent in other languages,
you absorb the error
but you're still up
and you can still do other things if you want to.
Like you can say that's all folks, right?
So what I'm gonna do
is I'm gonna kind of revert back to my code
to its original form
and I'm going to cause a panic in my background thread
and this will be the last bit of this demo.
So my background thread is gonna panic,
it's gonna fail.
But what I've done here in my main code
is I've gone for the the kind
of rather uncautious approach
where we just wait for the background thread to terminate
and then we just unwrap the result, okay?
If you unwrap a result that's an error
then our thread will also terminate.
So this, if we unwrap an error result
this will cause our main thread to terminate
and that's the end of the program
or that's the end of this thread.
Maybe there's another thread
above us that'll then pick up, okay?
But that will terminate our thread
and that's our main thread in the application.
So our application's gonna basically crash
or panic at that point.
Okay, maybe that's what you want.
Anyway let's see that happen.
So nothing's gonna happen
until the 10 second delay is up
because it's only after 10 seconds
that my background thread terminates
or then panics, okay?
And it does panic, doesn't it?
So the backbone thread panicked
deliberately panicking dude, okay?
And my main thread also panicked.
Like I said, when you unwrap an error result,
your thread, the main thread panics as well.
So the main thread has panicked
and it's here on line 27.
And because that's the main thread in the application
then basically our application,
our process terminates with an error.
So you have a choice.
It is, you know very common
when you kick off a background thread,
it is common to need to wait fit to finish.
Okay so you you do get back a handle
representing the thread
and you do want to join on the handle.
It's up to you whether then you just in a bit cavalier
that's the word I was looking for.
A little bit cavalier,
where you just say I'm gonna see if what's working.
Oh, it didn't.
A more cautious approach
is where you match
and you deal with a successful outcome
and an error outcome on an equal setting.