The next topic that I would like to cover is threads.
Threads allow a process to perform more than one task at a time.
And this is all very dependent on the type of system you have and the capabilities of it.
But for example, let's say that you were trying to load a browser and you were in charge of making
the program that does that.
You might have a thread that displays the images, another thread to retrieve data and threads for any
other functionality that needs a dedicated task.
And during this lesson, I will mainly be covering the threads.
There are a lot of different ways to use multi-threaded processes, and I'm going to shortly touch on
parallel computing and sort of the capabilities on that.
So just to get started, let's cover what are threads threads are a basic unit of CPU utilization.
This and depending on what the task is, threads may be good, but it's dependent on the task.
There is a lot of overhead and it takes a lot of CPU clock cycles to create and destroy threads within
a process.
But like it's in the name, these threads are used to create a multi-threaded application.
And when you use it properly, it will greatly increase the performance of your application.
As you can see, the threads share resources with other threads in the same process.
And as you can see, there is a lot of things that you can choose, such as How many threads do you
want in the process?
Would it be good to have 10 threads in one process or 100 threads in a process?
Well, you might say, Oh, there's 100 threads, so it's going to complete faster.
Well, that might not be the case because like I said, there is overhead creating 100 threads and destroying
them.
So it might be beneficial just to use 10 threads.
And there is a lot of sort of testing to figure out what the optimal solution is.
Just really quickly, I want to cover parallel computing and what you can do to accomplish parallel
computing.
There are a lot of different API libraries that are used in parallel computing.
And just in general, parallel computing is really cool because you are able to take a program that
might take 10 minutes to complete.
And when you use these libraries, you can take the runtime down all the way to like 10 seconds.
Let's say there is a lot that goes into creating a parallel program, however, but when you get good
at it, it will greatly increase the performance of your program.
There is a lot to learn here, such as when to use disposable versus non disposable threads, how many
threads to use, and so on.
If there is an interest in parallel computing, I can make a course covering those APIs.
It is pretty fresh in my mind, and I have done a lot with Carol Computing recently.
These are the libraries that I am familiar with pea threads which we'll be covering in this course.
Open MP, CUDA and MPI.
These are all really great libraries and they basically do the same thing.
But how they do it, it's some libraries are better than others, but I think it'd be a great course
if you guys are interested.
Definitely.
Let me know.
However, for the sake of this course, we will be covering key threads, so let's just get started
with the calls that you can do with threads, and this will help you accomplish your threading your
threaded applications.
The first system call is the EPP thread underscore create.
And as you can see, I didn't put any arguments right now because there are a lot of arguments and I
didn't want to write it out now.
We will be covering those in the actual examples.
This call creates a new threat, and like the other system calls, we've seen, it returns a zero f
success one.
If otherwise, this is how you will code.
When you want to create fear, you will use the Typekit threat underscore key and a point to my thread.
And then you actually call the command p threat underscore create and you pass in the thread name and
then some other details which we'll cover in the next slides.
The next system call is the P thread underscore Join.
As you see, I left out the arguments again and we will cover those in the coming slides.
This call waits for a thread to finish, and it returns zero if it's a success and one otherwise.
This is equivalent to doing a weight system, call in processes and also a barrier in some others to
some extent.
But that's sort of the basis if you want to.
It's basically waiting for a thread to finish, and a very common way to wait for threads to finish
is if you have a program that creates 10, let's say, 10 threads and you want to wait for all the threats
to complete executing before you move on with your main code, you will carry it for loop that it rates
from zero all the way to the number of threads, and it will join that thread using the thread joint.
So it's essentially waiting for every single thread to finish before the main program continues, executing
down sequentially to the rest of the way.
This is a very standard way on waiting for multiple threads to reach a certain point in the code.
And like I said, this is similar, but it's different to performing a barrier and some and the weight
in process is the next system call is the p threat underscore exit.
This is equivalent to doing the exit system call in processes.
And this just terminates a running thread and it returns nothing.
So now we're going to head over to my VM and do a couple of threads examples where we'll be covering
how to do thread creation, execution, merging.
And we're going to be passing arguments to a thread safe function, which is very important when using
threading.
OK, the first, third example that I want to show you is going to be a very simple program that just
creates a pea thread, waits for it to finish executing and then print some useful information to the
council so we can actually see what is happening.
The first thing, as always, is to create open up the manual page for the call that we want to use.
The first call that we need to use is the thread underscore create.
As you can see, this thread in our score, create creates a new threat.
That is exactly what we want.
We need to include the key thread age, which I've already done that.
And here's some more helpful information that you can read through if you're interested.
But as we'll see, it takes in four different arguments and we will have to make sure that we do that
properly.
The first one it takes in the thread it takes in an attribute, takes in, they start routine.
And lastly, some arguments for now, when we are utilizing our threats, they function.
We're just going to be passing in a null value.
But in the future, we will be passing in an integer, which we got to make sure it's thread safe because
there are some issues when you are passing in actual numbers in a for loop, for instance.
So to get started, the first thing that we have to do is create our thread.
In order to do that, we need a thread of Typekit thread on a square key.
So that's the first thing we're going to do is create a P3 discourse type type T and am going to call
it ID.
Next, we are going to be using this call now called P Threat underscore key.
And let's go ahead and p thread create.
We need to pass in our thread, which is just ID, and as you can see, it needs to be a pointer.
So we're going to go ahead and pass it in like that.
Next, it wants to give us the attribute.
For now, we can just leave that as null because it doesn't matter.
Next, we need to pass in the start routine.
Now this is going to be our threat save function, which we need to create.
But for now, it's going to call thread safe.
That's going to be the name of our function.
And lastly, we want some arguments.
And as I stated before, for now, we're just going to do that now.
But in the future, we will put some.
We're going to be passing in an actual value.
So once that is created, we're going to throw in a p thread join, which means it's going to wait at
this point for the thread to finish, which I need to pull it up.
But I just know it so we can just do a manual p thread.
And as you can see, this is joined when a terminated thread.
Join with the terminated thread and it takes in a thread and a return value.
So for now, ever turned out to just mean null, and we're waiting on this thread defense.
So once this thread is finished executing, it will continue on.
But it's going to wait at this point, and it's that doesn't really make sense to do it when there's
just one thread, but eventually when there's more threads, at least we can have the concept of going
there.
So now the only thing that we need to still add is our thread save function.
The way you do that is you create a void function and you have to make it with a pointer and you've
got thread safe and it's going to take in a you can name this anything you want.
But for now, let's do VAR p and let's go ahead and finish making this.
And all this functionality function is going to do is do a print saying hello from the thread new line.
You are, and that is all we want to do with that function, just so there are some more helpful things
to in the council so we can see where it is in the program.
We're going to throw in some prenup statements, not in the thread.
Go on.
And then it's going to go into the thread with this call is going to create the threat, enter the Thursday
function and then it's going to exit.
And then once it's done executing, we will throw in another print half saying after thread after,
after a thread finished.
OK, so just reviewing one more time, we created a threat, say, function that is simply just print
hello from the threat.
Then in our marine program, we created a ID for a threat that, with a type threat, underscore key.
And then we print to the council saying not in the threat.
Then we used a threat create call.
We pass in the thread and we are pointing it to the threat, say functions.
So this threat is going to enter into this thread safe function, then we are doing a P-3 join, which
means we are waiting for this threat to finish executing the threat safe function.
And then lastly, we are printing to the council that the threat finished and something to know when
you are compiling this programs that use threat by default, GCHQ does not include the Fed library,
so you have to include the library using a Dash LP thread argument.
So that is done by you.
Simply do IGCC typing, you threaten your program name and then type dash through LP thread, and this
will include deep thread library in your binary.
If you do without that.
You'll see that if there is some error saying undefined reference to P3, create P3 join.
However, if you add in Dash LP thread, no errors.
So let's go ahead.
And now that we have 8Ot out, we can go ahead and do that out.
And as you can see, it says not in the thread.
Hello.
From the thread after thread finished and that is exactly what we would expect to happen.
It prints not in the thread, then it creates a thread that goes into the thread safe function.
This thread safe function simply prints hello from the thread.
Then once the main program is, it sits here and waits for the thread to finish executing and then it
prints after thread finished.
So that was a very easy example, and we're going to move on to the next one.
This next example is going to be a little bit harder, but it will demonstrate how to properly create
more than one thread and to also pass in a specific variable for specific thread into a thread save
function in order to get started.
That's bringing up our manual page again.
P. Thread creates next.
We want to simply first create our variable.
However, this time since we are creating more than one thread, we want to actually create an array
of threads on order to do that.
We do it like we've done before, except now make it into array form and we're going to pass in a variable
called number of threads.
For now, we are going to set Int NUM threads equal to 10, and this is creating the variable.
The actual thread types.
And next, before in the last example, we just did a one p thread underscore create command.
And what that did was created a thread, but it was just one single thread in order to create more than
one thread.
You actually have to iterate over this command using a for loop or any sort of type loop for this was
going to enable zero i less than NUM threads and we're going to do a plus plus.
Oops!
And let's go ahead and bracket this off.
So we're going to iterate from zero all the way to nine, and we're going to call Pete thread career
and that's going to create the 10th race that we want.
Here we want to pass in the array number or the thread number before we just pass in the idea of it.
But now we have an array.
So we actually we need to use an index on this variable.
So our Pete thread array uses the name thread so we can iterate over threads using the AI variable.
So we're going to iterate over all these threads.
Next, we're going to use the same thing we've done before with null, the function that the Thread
C function that we want to use is just called thread safe.
And again, this thing can be anything.
And next, we are actually going to be passing in a variable for now, where it needs to be of void.
It needs to be a voice type so we can do a void.
Pointer and then drive, Fred, actually, for now, I want to just pass in the eye, so if we do I.
I want to show you something first.
So when this is creating a thread, it is going to be creating the thread for a certain thread.
No, it's going to call the thread safe.
No, and it's going to pass in the index of the thread.
This is also just the idea of the thread.
So if we go to the threads they function, we want to now take in the arguments args in this case and
we want to reference it in Thread ID, and we're going to create it into pointer and args.
And let's just do a print statement.
Hello from Fred.
And we're going to do the and and we're going to use the it needs to be there for more time.
OK, so what this is doing, it is creating 10 threads.
It's iterating over our thread type array.
It's going to be going into the threats, say function, and it should be passing in its AI index,
which I core stands from zero to 10.
Next, what we need to do is wait for all the threads to finish its work.
Now, let's say there are different types of threads in here, and you're calling different thread safe
functions.
You can add a if statement in here.
So if it is even threaded, you can set it to this thread site function.
If it's odd, you send it to another one.
The work is going to be finished at different times.
So what we want to do is wait for all the threads to finish before we continue on with our program.
So in order to do that, we will do a similar thing when we deal with creating before.
When there was just one thread, we did one P3 join.
However, now that we have 10 threads, we have to iterate over the thread joint command and make sure
that all of them are finished.
So for now, we're just going to create IG.
We can reuse them, but just to keep it separate.
We have AI for this loop and we're going to create another loop for J.
So for Jacob, Zero is less than number of threads.
J plus +, except now we want to do a P thread join and what we are doing is we are waiting for every
single thread to finish executing.
And you can just do like this if we go to our manual page for a p thread, join.
You'll see that it only takes in the thread and also the return values and return value which can leave
null.
But we are basically iterating from zero to 10, and we are waiting for every single thread to finish
executing.
After that, we can do a p thread exit, which it's not always necessary, but we can just throw it
in here for now and just so we can actually follow better what we are doing.
So this is hello from the thread.
So before it's creates all the threads, let's just do it quick.
The quick print statement where we do hello or actually this do not thread the new line.
And then let's do it will say not in line that will enter the thread and say hello from thread zero,
hello from third one, hello from and so on.
And that once it's joined, that means we are not in the threat anymore.
So this is going to be after the thread and this will be the fourth thread.
So let's go ahead and actually compile this program.
Let's go ahead and compile it.
Dom threads and a impassioned argument.
Looks like there's a quick error under the EPP thread.
Create so we can go ahead and try that again.
Clear this and run it.
So now this does kind of what we are expecting, but it doesn't look proper, so it says before thread,
then it goes ahead, creates the 10 threads and it calls the thread to say function.
However, you could see that is passing the variable 10 each time.
And that is how we are referencing this.
I variable this I variable is changing over and over and over.
So basically it's gone with the last I value that it gets, which is 10, because on the last iteration
it goes nine egos nine and then it goes back to the four and it goes A-plus plus.
So I is now 10.
It checks is 10 less the number of threads.
No.
So it leaves.
However, I is being referenced by all of these up here.
When we are referencing the way to fix this is we need to actually create an array for our arguments
that we might pass in.
And this is a standard method that is used a lot of times.
So this time we are going to carry a ray of ants apart.
P thread p thread args.
Let's just call thread args and it's just going to be the size of threads.
And then inside of here, we actually want to assign what the arguments are for each thread and we're
going to use the same indexes.
So the P thread zero is going to be argument zero one, one two and so on.
So what we simply want to do is assign the thread args of equal to the index that it is actually at.
And what this is doing is creating basically a hard copy of that value that we want to pass on.
So instead of passing on, I and I the which is the overall index for the loop, we want to pass in
the individual index that is stored in the threat argument array.
And we just simply do that by passing this here and index I.
So we are basically going to the index within this array, which is equal to the index in this array
is kind of confusing, but this is how you have to handle thread safe functions.
So now it will properly execute.
In just a quick note, if you remember this process, scheduler does not know which order these threads
will be executed and so we can run at one time and it might go hello from thread one two three four
five six seven eight nine 10.
However, we can run it again and might say hello from that thread to six, four, three and so on.
So let's go ahead and just compile this.
For now, I need to save it over here.
Let's go ahead.
A copilot with the LP thread, and as you can see, we have our error.
It's clear as possible.
So what is something unique about the threads is that remember, the scheduler depends on how the threads
are called, even though one time it might be in this order.
If we call this exact same program, it might execute this in a different order and say hello from thread
one first instead of six.
So let's do this a couple of times until we get a different order.
And like a lot of times when you run it, once it sort of sticks to the exact same schedule.
But if you can see right here, I think it's switched.
So we go six seven eight nine five.
Here goes six seven eight nine four.
So although that seems very minor, that is something to consider is that you do not control in what
order these threads are executing.
And I just found an error over the quick and the reason why this is not putting proper use, I accidentally
use the wrong index right here.
We need to add this as a j.
So it was printing it what they thought.
Everything was completely because he was using just one eye index, which was 10.
So it was automatically done and then it just print after threat before even called all the threads.
So now we go ahead and compile our program threads and then do a Dash LP thread and do eight out.
As you can see, it goes before thread and then it prints all of the hell from thread.
There is 10 of here and then it prints after thread, so that's a really good example just to go over
it again.
We have a thread safe function that properly handles passing arguments from the culling program to the
threats function.
This is how you have to do it and then you have to put a pointer here and it will print the correct
fed number and will handle that argument properly.
In the main program, we created an array of Typekit thread on equity.
And we also have a thread argument which is used to hold the arguments that we want to pass using the
P3 to command into our thread safe function.
So first, we have two main loops.
The first main loop is the for loop, which is actually creating 10 threads.
And then next, we are just waiting for the 10 threads to finish.
And that is the basis of threads.