At first sight, this looks like not-pretty-but-correct C++ or C (an easy way to be sure is to compile it). Includes are missing (<windows.h>
, <process.h>
, and <time.h>
) but otherwise it compiles fine.
Note that clock
and Sleep
are not terribly accurate, and Sleep
is not terribly reliable either. On the average, the thread function should kind of work as intended, though (give or take a few percent of variation).
However, regarding question 2) you should replace the last while(1){}
with something that blocks rather than spins (e.g. WaitForSingleObject
or Sleep
if you will). otherwise the entire program will not have 50% load on a quadcore. You will have 100% load on one core due to the main thread, plus the 4x 50% from your four workers. This will obviously sum up to more than 50% per core (and will cause threads to bounce from one core to the other, resulting in nasty side effects).
Using Task Manager or a similar utility to verify whether you get the load you want is a good option (and since it's the easiest solution, it's also the best one).
Also do note that simulating load in such a way will probably kind of work, but is not 100% reliable.
There might be effects (memory, execution units) that are hard to predict. Assume for example that you're using 100% of the CPU's integer execution units with this loop (reasonable assumption) but zero of it's floating point or SSE units. Modern CPUs may share resources between real or logical cores, and you might not be able to predict exactly what effects you get. Or, another thread may be memory bound or having significant page faults, so taking away CPU time won't affect it nearly as much as you think (might in fact give it enough time to make prefetching work better). Or, it might block on AGP transfers. Or, something else you can't tell.
EDIT:
Improved version, shorter code that fixes a few issues and also works as intended:
- Uses
clock_t
for the value returned by clock
(which is technically "more correct" than using a not specially typedef
'd integer. Incidentially, that's probably the very reason why the original code does not work as intended, since clock_t
is a signed integer under Win32. The condition in if()
always evaluates true
, so the workers sleep almost all the time, consuming no CPU.
- Less code, less complicated math when spinning. Computes a wakeup time 50 ticks in the future and spins until that time is reached.
- Uses
getchar
to block the program at the end. This does not burn CPU time, and it allows you to end the program by pressing Enter. Threads are not properly ended as one would normally do, but in this simple case it's probably OK to just let the OS terminate them as the process exits.
- Like the original code, this assumes that
clock
and Sleep
use the same ticks. That is admittedly a bold assumption, but it holds true under Win32 which you used in the original code (both "ticks" are milliseconds). C++ doesn't have anything like Sleep
(without boost::thread
, or C++11 std::thread
), so if non-Windows portability is intended, you'd have to rethink anyway.
- Like the original code, it relies on functions (
clock
and Sleep
) which are unprecise and unreliable. Sleep(50)
equals Sleep(63)
on my system without using timeBeginPeriod
. Nevertheless, the program works "almost perfectly", resulting in a 50% +/- 0.5% load on my machine.
Like the original code, this does not take thread priorities into account. A process that has a higher than normal priority class will be entirely unimpressed by this throttling code, because that is how the Windows scheduler works.
#include <windows.h>
#include <process.h>
#include <time.h>
#include <stdio.h>
void task1(void *)
{
while(1)
{
clock_t wakeup = clock() + 50;
while(clock() < wakeup) {}
Sleep(50);
}
}
int main(int, char**)
{
int ThreadNr;
for(int i=0; i < 4; i++) _beginthread( task1, 0, &ThreadNr );
(void) getchar();
return 0;
}