12/10/08

Tiny code for Using Multicore CPU Multithreading

Its easier than most people think to use multicores, even with very small code.
The trick is to realise that a CPU, when given more than one thread, will try to run those threads on different cores where possible. I used multithreading (and hence multicore) in a 1k once. I wanted the music in a different thread because I had no space for a real timer for the music. So, the music was written as a function that played the next note. The function was called from the main loop. Timing issues connected to drawing the graphics meant the note was played slightly off beat at times and it was very disconcerting.

So instead I changed the music routine to be:

Loop:
Issue notes
Sleep for some time


Then I set it up in another thread before, entering the main loop, using:

SetThreadPriority(_beginthread( &addTune,0,0), THREAD_PRIORITY_TIME_CRITICAL);

(Watch out this was done using GCC - VC++ may need other, more precise, syntax)
beginthread kicks off a new thread with the function addTune as the first function called in that thread when it starts. SetThreadPriority ensures that even on a single core the music thread will have higher priority than the main graphics thread and the music will not suffer tiny stalls. The ear is more sensitive to this than the eye to the occassional graphics frame dropped.

You need to include process.h for the thread calls above.

On multiple cores this would now be configured by the O/S to be two threads running on two cores.

What about synch? In the 1k I synched the music to the graphics. This means communicating between the two threads (and cores). Again this is deceptively simple.
A variable is declared and the music thread assigns it each time is plays a new note. The drawing thread uses the variable (read only) to decide how to move the graphics just as normal. Globals can be used to communicate between threads and even to synchronise them.

Threads and cores can be very tricky beasts in true parallel programming (I used to work at Edinburgh Parallel Computing Centre on the supercomputers there) but they can also be used in even a 1k intro!

Addendum, to avoid linking with MSVCRT and use win32 functions instead, its possible to use syntax like this in VC++:

SetThreadPriority((HANDLE)CreateThread( NULL, 0,
(LPTHREAD_START_ROUTINE)&addTune,0,0,0), THREAD_PRIORITY_TIME_CRITICAL);