Splitting the computation of a program into multiple threads might improve performance since we are
taking advantage of multiple tasks at the same time.
But with this comes increased complexity.
We might run into issues like race conditions where threads are accessing data or resources inconsistently.
Or deadlocks which occur when two threads are waiting for each other to finish.
Therefore, neither thread finishes.
But we will dive into those concepts a little later on in this section.
So for now, let's look at how we can create a thread.
The first thing we need to do is bring it in to scope, which is in standard thread.
And now to create a thread we just use thread spawn.
And then for now we just want our thread to print out a message and we'll say hello from a thread.
Now let's run this.
And we'll see that nothing was printed out.
But then we run it again.
And hello from a thread was printed out.
And then if we run it a third time, nothing was printed out.
So why is this happening?
Well, it's because the main thread is actually finishing before our thread spawns and is able to print
out our message.
So what we can do to just make sure that we give our thread time to be created and then print out our
message for us.
We will use another crate called duration and what duration is going to do for us?
It's going to allow us to make our main thread.
Sleep.
So we'll say.
Thread sleep duration from seconds and then we'll say one.
So we just want our main thread to sleep for one second.
So now if we run it, we see hello from a thread ran.
But then you can also see that there is a little pause and that pause is our thread sleeping for one
second?
Well, this isn't actually the best way to do this, so there is a better way of doing it.
And it is by using the join method so we can actually delete all of this.
And we see that spawn returns a.
Boeing handle so we can say let handle equal and then the joint handle that gets returned and now we
can say handle dot join, dot wrap.
And what join is is it's a form of blocking.
And blocking a thread means that the thread stops running until the thread represented by the handle.
Join terminates.
Excuse me.
Join.
Handle.
So we're going to block our main thread until our thread that we is.
Excuse me.
Until our joint handle that we assign to handle.
Is finished executing, and that is what Jordan is going to do for us.
So now we can say we'll say print line
hello from main.
And now if we run this, we see that we got hello from thread and then hello from Maine.
So.
This will always pan out prior to this because we told our main thread to wait until this thread has
completed its task.
So now let's move into a little bit more in depth reading.
So let's create a vector and we'll just call it V and we'll assign it the values.
One, two and three.
And then we want to spawn another thread.
And for now, we will move this forward out of here.
And now we want to print out our vector.
Well, we see that we get an air.
And our air says that our closure, which you can see that we have denoted here, may outlive the current
function, but it borrows our vector V, which is owned by the current function.
So that word that we originally got rid of, we can now put it back in and it is called Move.
And Move is going to allow us to force the closure to take ownership of the values it uses.
So now if we try to run this,
it runs flawlessly because we told our closure to take ownership of the V vector.
So now let's look at how we can spawn multiple threads.
So we'll keep our current vector and then we'll create another vector that's going to handle.
All the threads that we spawn.
So I'm going to comment this out since we want to use our vector again.
But now we can say.
For.
E element an RV vector.
We want thread.
No thread handles and we want to push in spawning.
Vectors in.
Now, let's just format this to make it look a little better.
All right, so what are we doing here?
So we created a new vector called thread handles.
And for every element inside our vector.
So one, two and three, we are going to push in the result.
So a.
Join handle.
We're going to push in a join handle into our thread handles vector.
So what this is going to do, it's going to create three vectors for us.
And they're going to be running.
So while they're running, I want my main function to print.
Main thread.
Excuse me.
Our main I want our main thread to print out that it's the main thread.
And now for handle and thread handles, we need them to join.
That way we make sure that they finish executing and print out the thread that they are.
So we'll run this and we see we got main thread thread.
One, two, three.
And now we see we have main thread thread three or excuse me, thread two, thread one and thread three.
So the order that you might see may very differently than mine.
But it's a good way to show that certain threads might finish executing, not in the order that they
were spawned up in.
So I just wanted to point that out to you.
And this lecture was just a simple demonstration on how to spawn a thread, how to join the threads,
and also how to use the mov keyword to force a closure to take ownership of the values.
Because all of this will be important as we continue on learning more about threads as we continue in
this section.