[Autogenerated] let's continue by writing the count primes
function which each thread is supposed to run.
And so we know that every threat function always looks the same.
That would be uh count primes returns the D.
Word and expects to provide some kind of P void.
Now we know that this point or to avoid is not simply a pointer to void,
but in fact it provides the thread data we need to work with.
So let's just grab that thread data using this program.
Just cast it to uh to the pointer to thread data and now we have
everything we need in order to perform the calculation.
So this thread is going to start running from
whatever first was provided in data.
It's going to run until we get to the last that was provided in the data
including the last and plus plus here to move to the next number.
If you're wondering about this symbol here.
Don't worry.
The C language hasn't changed while you were away.
It's just a matter of putting these two symbols together as you would expect.
How?
However I'm using a fund that has these ligatures.
That makes some changes to how symbols look for a
certain combination of symbols.
This particular fund is called cascadia code and if you care,
it's a Microsoft phone,
you can download that from GitHub There are other similar funds
so I like it but you of course don't have to.
So don't worry.
It's the same thing is just using less than and equals together
just being displayed slightly differently.
So for every one of these numbers,
we have to figure out whether a number is prime or not.
So I'm going to call a helper function which will right in the moment that's
going to check whether I is a prime number and if it is,
let's just increment the count and once we're done there's not
much left to do except put the final result into the count member
where it's expected by the main code.
Let's just put it there and we can return anything really because
nobody really cares about the return value here.
Although it could return count as well just for for fun.
So each thread is just doing its work based on the
range that it is supposed to work on.
So everything is going to do exactly the same thing
but working on different numbers, different data and this is like I said,
very common um, in multi threaded or proud algorithms.
So the last piece of the puzzle is the east prime function.
Let's write that function now.
So here's is prime.
The purpose of his prime is to take a number and figure out whether it's a
prime number and there are many ways of doing that as well.
I'm going to use one of the simplest ones and the simplest ones
means we need to use the square root function to figure out the
square root of the number and then just perform a loop from two to
the square root of the number.
If the number divides by the region number is divided by the loop number
without any remainder that this is definitely not a prime number,
we can bail out quickly and return false.
However,
if we get to the end of the loop and and it's not
divisible exactly by any one of these numbers,
then that's a prime number we can return to.
And just to make sure we compile that correctly.
Let's add and include for math dot H to get access to the
S security or square root function.
And that should be all that we need.
We can definitely also display some stuff like when a
thread starts with a thread ends.
But let me just uh dispense with that for now.
Let's just write something here like uh starting or working just something
very very simple and then we'll get the final result.
Now in order to Well, of course we have to initialize the variable.
My bad.
So it compiles just fine.
At least supposed to be compiling fine.
Maybe not exactly because I failed to add total here, my bed again.
Well maybe I should call it count and now it compiles fine.
But to to make uh performance checks in a real manner,
it's important to compile our application in release build
so that we get the full compiler optimizations so it runs
as fast as it possibly can.
So now let's just open a command window here.
Let me just open a command window and go to this particular directory.
So you can run these things from the command line here with
the number of threats of our choosing.
So let's use DEV and primes X 60 for release.
This is where we find our executable.
And just last one last thing, let's just add here.
The number of threads were actually using.
So we have that on the record properly.
So let's start with using a single thread so that we have
some kind of baseline to work with.
So let's do that.
So it uses a single threat to perform the calculation so we can get a
sense of the count of prime numbers and the time it takes.
So as you can see it's done, uh it took something like six and something seconds.
And the number of primes is as you see here now,
since it was fairly quick, let me just increase the number of numbers.
So we have a bit more interesting numbers to look at once we add more threats.
Let's try this again To see how many prime numbers are in the range
from 3-25 million using a single thread of execution,
which means that a single processor is going to be
used and we get 8.8 seconds roughly.
Okay, great.
Let's now go ahead and increase the number of threats to two.
Just to see the improvement that we expect to get.
And indeed we get an improvement but notice the improvement is not linear.
So the time it takes for this calculation to now happen is
not half of the time that it took a single threat to work
and to do the same kind of job.
And so this is something we might want to find explanation for.
Let's see if this thing persist.
Let's use four threats and I'm using powers of two just for convenience.
We can use any number of threats really.
So with four threats, we get the calculation to uh to finish earlier,
which is of course great.
But again,
if you compare that to the initial number of
seconds it took for a single thread.
It's not a linear improvements.
Not a quarter of the time, it's higher than that.
Now.
My system has eight threads.
Sorry, eight processors.
This particular system has eight processors late.
Let's take a look at the performance.
Uh here in task Manager,
you can see there are eight logical processors on this system,
which means that at least in theory it seems that using eight threats
would be the best approach in order to get this thing running as quickly
as possible because we have eight processors,
if we have eight threats, then that should be the best.
Right.
Let's see.
So with eight threads, it is running definitely faster.
It took almost two seconds.
But again,
if you compare that from to the initial single
thread case it's not 1/8 of the time.
It's roughly one quarter of the time, which is not exactly,
perhaps as we expect, the improvement is not not linear,
but it does exist.
So what happens if I use even more threats?
Let's go with something like maybe 10 threads.
What would happen here?
Let's try.
And apparently we get slightly improved timing,
Which might be very looking, very weird.
I mean, shouldn't it actually be worse?
I mean we only have eight processors if using 10 threads,
we know that at any point in time, only eight threats can run at the same time,
but still we get better results.
Maybe we can continue with that and add even more threats.
How about 15 threats?
And we get another improvement, although very small steel and improvement,
which again perhaps doesn't make sense based on what we know so far.
Let's continue with something like 30 threats.
Maybe that would be even better.
And indeed we get another slight improvement.
So that seems a bit weird.
Why do we get this particular behavior?
Maybe you can just increase that to even more threats.
But at this point we can see we start seeing some diminishing returns here.
So apparently now time started to be worse and still
doesn't really explain what we have here.
So, the two things we need to explain.
The first one is why don't we get linear improvement?
And the second one is why do we have better results when
we have more threats than processors.
In fact, the answers are in the code, somewhere in the code.
So I suggest you think about it a little bit and see if you can
figure out why we're getting this particular behavior.
I even encourage you, of course, to download the code and try it out yourself.