[Autogenerated] let's make this example slightly more interesting.
Instead of passing now here let's pass something else.
Let's define X.
Here that has some value.
Let's pass the address of X to the function to the thread function.
And here once we get that we want to grab that value let's say we would like
to just multiply it by itself as as a very simple example.
So we know we have here something which is a pointer to an integer and
we know that because we're writing both sides here,
writing the client code creating the thread and
writing the threat function itself.
So I'm going to cast the parameter to an in start to appoint an
integer and simply the reference that to get the data.
And then I can return something like data times data to
make it slightly more interesting if we run this we should
see something that we expect, we see the threads Running.
So we have the main thread that is mostly waiting and we have the worker thread
that is doing the actual work and the result we get is 400,
which is what we expect.
Now let's make things slightly even more interesting
by creating yet another threat.
Let's say I want to create another threat that's going
to run exactly the same function.
But with work with different data and this is actually fairly common.
You might have lots of data and you need to process them in exactly the same way
but you want to do that concurrently to utilize the multiple course on your
system let's just add another create thread call here and capture the handling a
different variable called age thread too.
And let me define another variable here, called Y and give it some value.
Let's pass here the address of why?
So now we have the main threat and two threads running concurrently while
the main thread is displaying this main thread caption.
But now we want to wait for both of these threats to
terminate and not just one of them.
Let's say that we want to grab the details of the results
from both threats before we move on.
The wait for single object function is not good enough.
And although we can make another wait for single object function call
for h threat to that would be slightly inefficient.
And there is an alternative which is calling a more bigger function,
so to speak, which is wait for multiple objects,
which the act provides the same functionality as wait for
single object but it has a more possibilities.
And the basic ideas,
you can wait for a number of kernel objects to become signaled,
either one of them or all of them.
In this case we want all of them.
And one of the parameters to the function would allow us to specify that.
So the first parameter is how many handles you would like to wait on how
many objects you would like to wait on that would be to in this case and
they need to provide an array of handles.
So I didn't create these variables as an array and of course we can do that,
but let's just create a local array here that will simply be
initialized with H thread and H thread too.
And so now we can pass H here as the address where the race starts.
So now we have the opportunity here to work with these two handles.
It's going to be slightly more elegant.
You can say something like count of H,
which simply returns the number of elements in in the H array here.
This is just a macro.
This will make it easier if you later decide to add even more threats.
The next parameter is whether you'd like to wait for all of these threats to
become signaled or just one of them and we want all of them.
So too is the value to specify here and again we can
specify limited interval for waiting.
But again,
I'm going to use infinite here saying I'm going to I'm
willing to wait for as long as it takes.
So now that at this point the stuff the work is done,
but we need to collect the information for both of these threats.
So get exit code thread in this way is not good enough.
We need to use all the threats.
Let's just loop around so again,
we can use just the plane to or use count of H so you can
access the threads using using the H array instead of using
the individual H thread or H.
Two handles because that's essentially the same thing.
So I can grab the exit code for the first thread and then
the second one using the array here.
And I can say something like, well thread with a particular I.
D.
Uh is done and the results from that thread happens to be so
and so and so here we can get the thread I.
D.
Based on the handle, This is what I mentioned earlier,
so it's possible to get a thread I.
D.
By using a handle to it by using the get thread, IDE function.
And then we have the result, which is the code we received back.
So we can now end this loop at least for now.
And perhaps let's uh make this slightly more interesting and
maybe want to capture the sum of all these codes.
So I can just grab the sum here and add that uh code to the sum.
And at this point, in fact,
I can even close the handle to the current threat
because I won't be needing that anymore.
So once we do that,
we can say the final result is just call that total is going to be
whatever was accumulated in some and there's no need to close any
handle because that's already been done here.
So this is slightly more interesting.
Let's run it and see what that looks like here goes.
So you can see two worker threads running And they're done in
roughly the same time and we get the results,
we expect the first thread was calculating 400,
the second one was calculating 100 because that's 10
times 10 and the total is 500.
We can make it again slightly more interesting by changing the sleep here
to be slightly more randomized by using the threat ide as as a way to um
to kind of specify how long to wait just for to make things slightly more
interesting and more randomized, so to speak.
So if we try this again now, each thread will be done in different times,
so not done at the same time and it might be slightly different
depending on their actual generated thread,
IDE just to show that it works and the main thread will wait for
as long as it takes until both of these threads are done and we
still get of course the same result.
Another thing I'd like to mention at this point is what would happen if I
just do something like this instead of having this Y here,
maybe I can do create thread here and then change X to 10 and
then just pass the same X here while it has the different new
value and maybe why is really redundant?
We not, we don't really need it.
So I suggest you pause the video at this point and try to figure out what
would happen when I run this application right now.
So hopefully you have some kind of guess, let me run it.
And so what you find here is that perhaps curiously we get results of
100 from both of the threats and the total is 200.
Apparently the value of 20 here was somehow lost while running this code.
And this is one case where you see where threat synchronization is
really required because what we have here is a data race and the data
is occurs when you have two or more threats that access the same
memory location where at least one of them is writing and this is
exactly what happens here.
So notice what happens when I call create thread.
The first thread running do work, starts execution.
However,
it takes a few microseconds or for you to actually start
executing and then I change X to 10 before the thread gets a
chance to actually execute its code.
So once it starts executing the code, the parameter has already changed to 10.
So 20 essentially is lost because the threat is not fast enough to
start before I change X year to 10 and that's why it was very
important to use the y variable previously because in this case there
is no data race because it's different memory locations and in that
case we don't have any issues.
Just something to kind of put your mind to or kind of
consider when you're writing multi threaded code