- Rust provides a simple API,
which allows you to manage threads manually.
All of the functions you need are in the std thread module.
And the API allows you to spawn a thread,
which means to create it.
You can join the thread,
which means to wait for it to finish.
You can move data into a thread if it needs some context,
and you can communicate data between threads.
There's a mechanism we'll have a look at in this lesson
called a channel like a pipeline
which allows data from one thread
to be sent into another one
without having to worry about things like lock in.
So that's the preferred way to communicate data
between one thread and another using a channel
as we shall see.
Okay, so to spawn the thread
you call the std thread spawn function,
the spawn function in the thread module in the std create.
And when you call the spawn function,
you pass a closure as a parameter,
a block of code to say run that code in a thread.
Okay, so when you call the spawn function
Rust creates a system thread on your operating system,
and executes your closure code on that thread
as you would expect.
Here's a simple example,
I called the thread spawn function,
and I've given it a simple closure here.
This closure will be executed
on the other thread, on the other system thread.
The main thread will continue to execute in parallel.
Every thread that you create in Rust has a different id,
and you can get the id like this,
you can say thread::current,
and then upon the object returned by the current function,
you can say .id, and that can be useful for login purposes.
You know, it's quite useful when you have a real system
to log messages and the thread id
can be useful to help you diagnose problems.
If you have a problem, what thread did the problem occur on?
The id gives you that.
You can also tell a thread to sleep for specified duration,
you call the thread sleep function,
probably would've guessed that.
You pass in a duration,
there's actually a class, a structure, I should say,
called duration, and it specifies
how long you wanna wait for in seconds, for example.
So it's actually quite straightforward,
we'll have a look at an example.
The project for this lesson
is lesson 14 multithreading concurrency.
Okay, so here it is, in the Rustdev folder,
lesson 14 multithreading concurrency.
So if you open that folder in the code editor,
I'll tell you the files we're going to look at.
For this demo, we're going to look at obviously the main.rs,
which is our entry point,
and the demo file, demo spawning threads,
and then we'll run it.
Okay, so let's take a look at the code
and then we'll run it.
Okay, here we are, so in the main entry code
let's run the first demo, demo spawning threads,
let's uncomment that, and it's here.
So little message to welcome me in.
Notice, I've imported the std thread module,
so I can just use thread directly here.
Obviously, if I hadn't imported std thread,
I'd have to fully qualify it here,
std thread and std thread,
again in various other places as well.
So it makes it easier
if you just import it in the first place.
Right, so when the application starts,
the main thread will come in here,
and the main thread will call this function,
and that will cause a second thread to be created.
It usually takes, you know, a few milliseconds
for that other thread to actually get going.
So it'll take a few milliseconds,
but sooner rather than later
this closure will be executed on a separate thread.
And on that separate thread,
oh, actually what I should say
is the thread spawn function returns immediately.
Okay, so as soon as you call it
it'll kind of kick off this background thread,
but the main thread will continue immediately
to carry on with the rest of the function, okay.
So the main thread will continue to execute this
whilst the other thread is getting started.
So when the other thread has been started
kind of in parallel to the main thread,
it loops around 10 times
and it prints out thread current id.
So we print out the current thread id
using the debug formatter,
and the loop counter 0 through to 10,
and then we sleep for one second.
Okay, so the background thread will sleep for 10 seconds,
every one second, it'll output one,
and then one second later it'll put two,
and then one second later it'll output three.
So this background thread
is gonna take 10 seconds to finish.
Okay, let's have a look at the main thread,
the main thread will be continuing to process all this time,
and that loops around five times on the main thread
and it displays the thread id for the main thread.
So we're gonna get two sets of messages
being displayed here,
the messages displayed by the main thread.
Okay, and we can see the id,
and interspersed with that
'cause I've got a four second delay here.
That's quite a long delay, isn't it?
So what's gonna happen is this inner loop
is gonna spin around quite quickly,
there's gonna be a one second sleep.
So that thing's going to loop around quite quickly.
Every one second it will output another message like that,
and then in a relatively slow loop
on the outside, on the main thread,
every four seconds the main thread will output a message.
Okay, I'm just doing the maths here.
This inner thread is going to take 10 seconds to finish.
Okay, so that's gonna finish quite quickly.
This main thread is going to take,
if I'm looping around five times
and each time I'm gonna basically sleep for four seconds,
that's gonna take 20 seconds to complete.
So this inner thread will complete within 10 seconds,
and then terminate as soon as your code
falls off the end of the closure,
that's the end of that thread.
The main thread will continue in its four second loop here
to eventually print out 100 through to 105.
I think that should make sense actually when we run it,
let's have a quick look and see.
Okay, so cargo run.
So it's download independencies specified in my toml file.
Okay, so notice the output,
we've got two threads you can see.
Thread one is the main thread,
which is looping on four-second timer.
Thread two is the background thread,
and that looped around fairly quickly.
Now, I'm still waiting for the outer thread,
the main thread to reach 105,
every four seconds it loops around again,
and another four seconds, and then it terminates.
Okay, so that actually makes sense, a simple example,
but you can kind of see the dynamism of it.
So the main thread came in, thread one as it turns out,
it kicked off this other thread.
It took a little while for this other thread to get started,
so even though we started the other thread here,
you notice that this main thread
continued a little bit first,
so the main thread managed to get this far,
and it displayed its first value 100.
It managed to get that far
before this other thread managed to wipe its feet,
and actually get started.
And then this then looped around quite quickly,
everyone second thread number two
was displaying the number four.
And then it was one second delay, number five,
number six, number seven, number eight.
And you can see because of the four second delay
on the main thread, that's gonna quite a low periodicity.
Whereas my inner thread with a one second delay
is looping around more quickly.
Right, so here's a secret.
When I was writing this demo, I wanted to make,
I haven't talked about how to wait
for another thread to finish yet.
So I was quite careful
that this inner thread finished first, okay?
And then this outer thread,
as soon as this outer thread finished,
then the application terminated.
I was quite careful to make sure that this then,
I didn't have to wait for this thing to finish,
it finished first.
So that as soon as my main thread finished,
it was okay to finish the whole application.
What we're going to look at in the next example
is how to wait for a thread that's longer running than us.
So the main thread would like to terminate more quickly,
but the inner thread is taking longer.
So we can say, let's wait for that other thread to finish
before the main thread finishes.
So that's coming up in the next example,
it'll be an example of the join function.
That's the next example coming up.