Tricks of the Windows Game Programming Gurus:Algorithms, Data Structures, Memory Management, and Multithreading

All ITKnowledge Source Code Search Tips Advanced Search |

| Tricks of the Windows Game Programming Gurus by Andre LaMothe Sams, Macmillan Computer Publishing ISBN: 0672313618 Pub Date: 09/27/99

Search this book:

Previous | Table of Contents | Next

The program is very simple. As usual, you create the secondary thread and then, right away, you enter into the printing loop. When it terminates, the `WaitForSingleObject()` is called. If you had more work to do in the primary thread, you would do it. But in this case you don’t, so you just enter into the wait function and wait. If you run the program with `SYSMON.EXE` active, you’ll see that there is almost no processor usage when the wait function is entered, whereas there would be if you used a busy loop.

Before moving on to the next example and multiple threads, there is a little trick you can do with `WaitForSingleObject()`. Let’s say that you want to know the status of a thread at this moment, but you don’t want to wait for it to terminate. This can be done by making a `NULL` call to `WaitForSingleObject()`, shown here:

    //…code

    DWORD state = WaitForSingleObject(thread_handle, 0);  // get the status

    // test the status

    if (state==WAIT_OBJECT_0) { // thread is signaled, i.e. terminated }

    else

       if (state==WAIT_TIMEOUT) { // thread is still running }

    //…code

Simple enough. This is a great way to test if a particular thread has terminated. This, coupled with the global termination message, is a very robust method to terminate a thread and check if it was actually terminated in a real-time loop when you don’t want to wait for the termination until it happens.

Waiting for Multiple Objects

You’re almost done. The last `Wait*()` class function waits on multiple objects or threads to signal. Let’s make a program that uses this function. All you need to do is create an array of threads and then pass the array of handles to `WaitForMultipleObjects()`, along with a couple of parameters.

When the function returns, if all went well, all the threads will have terminated. `DEMO11_9.CPP[vbar]EXE` is similar to `DEMO11_8.CPP[vbar]EXE`, except that it creates multiple threads and then the primary thread waits for all of them to terminate. Again, you don’t use a global termination flag because you already know how to. Each secondary thread simply runs a few cycles and then terminates. The source for `DEMO11_9.CPP` is listed here for your review:

    // DEMO11_9.CPP -An example use of

    // WaitForMultipleObjects(…)

    // INCLUDES ///////////////////////////////////////////////////

    #define WIN32_LEAN_AND_MEAN  // make sure certain headers

    // are included correctly

    #include <windows.h>         // include the standard windows stuff

    #include <windowsx.h>        // include the 32 bit stuff

    #include <conio.h>

    #include <stdlib.h>

    #include <stdarg.h>

    #include <stdio.h>

    #include <math.h>

    #include <io.h>

    #include <fcntl.h>

    // DEFINES ///////////////////////////////////////////////////

    #define MAX_THREADS 3

    // PROTOTYPES /////////////////////////////////////////////////

    DWORD WINAPI Printer_Thread(LPVOID data);

    // GLOBALS ////////////////////////////////////////////////////

    // FUNCTIONS //////////////////////////////////////////////////

    DWORD WINAPI Printer_Thread(LPVOID data)

    {

    // this thread function simply prints out data 50

    // times with a slight delay

    for (int index=0; index<50; index++)

        {

        printf("%d ",(int)data+1); // output a single character

        Sleep(100);               // sleep a little to slow things down

        } // end for index

    // just return the data sent to the thread function

    return((DWORD)data);

    } // end Printer_Thread

    // MAIN ////////////////////////////////////////////////////////

    void main(void)

    {

    HANDLE thread_handle[MAX_THREADS]; // this holds the

                                       // handles to the threads

    DWORD  thread_id[MAX_THREADS];      // this holds the ids of the threads

    // start with a blank line

    printf("\nStarting all threads…\n");

    // create the thread, IRL we would check for errors

    for (int index=0; index<MAX_THREADS; index++)

        {

        thread_handle[index] = CreateThread(NULL, // default security

                                0,        // default stack

                    Printer_Thread,// use this thread function

                    (LPVOID)index, // user data sent to thread

                    0,        // creation flags, 0=start now.

                    &thread_id[index]);    // send id back in this var

        } // end for index

    // now enter into printing loop,

    // make sure this takes less time than the threads

    // so it finishes first

    for (index=0; index<25; index++)

        {

        printf("4 ");

        Sleep(100);

        } // end for index

    // now wait for all the threads to signal termination

    WaitForMultipleObjects(MAX_THREADS, // number of threads to wait for

                       thread_handle,  // handles to threads

                       TRUE,           // wait for all?

                       INFINITE);      // time to wait,INFINITE = forever

    // at this point the threads should all be dead, so close handles

    for (index=0; index<MAX_THREADS; index++)

        CloseHandle(thread_handle[index]);

    // end with a blank line

    printf("\nAll threads terminated.\n");

    } // end main

Sample output:

    Starting all threads…

    4 1 2 3 4 1 2 3 1 4 2 3 2 4 1 3 1 4 2 3 2 4 1 3

    1 4 2 3 2 4 1 3 1 4 2 3 2 4 1 3 1 4 2 3 2 4 1 3

    1 4 2 3 2 4 1 3 1 4 2 3 2 4 1 3 1 4 2 3 2 4 1 3

    1 4 2 3 2 4 1 3 1 4 2 3 2 4 1 3 1 4 2 3 2 4 1 3

    1 4 2 3 2 1 3 2 1 3 2 1 3 2 1 3 2 1 3 2 1 3 2 1

    3 2 1 3 2 1 3 2 1 3 2 1 3 2 1 3 2 1 3 2 1 3 2 1

    3 2 1 3 2 1 3 2 1 3 2 1 3 2 1 3 2 1 3 2 1 3 2 1 3 2 1 3 2 1 3

    All threads terminated.

The sample output is what you’d expect. All threads print along with the primary thread (which prints 4’s for a bit), but when the loop in the primary thread is complete, the secondary threads continue until they all finish. Once all the threads terminate, the primary thread terminates because it is blocked from termination via the `WaitForMultipleObjects()`.

Previous | Table of Contents | Next

Copyright © Macmillan Computer Publishing, Inc.

Products | Contact Us | About Us | Privacy | Ad Info | Home
Use of this site is subject to certain Terms & Conditions, Copyright © 1996-2000 EarthWeb Inc. All rights reserved. Reproduction in whole or in part in any form or medium without express written permission of EarthWeb is prohibited. Read EarthWeb's privacy statement.