Using Busy Waiting


What is it:

Sitting in a tight loop polling a resource such as the control pad, or using tight loops for timing or synchronization.

Why it's bad:

Degrades the performance of the multitasking system by starving lower-priority tasks and unnecessarily stealing time from tasks of equal priority.

What to do

Use wait calls like GetControlPad(), WaitVBL(), or WaitIO() instead of polling.

Discussion and Example

This section discusses two examples that rely on busy waiting, pointing out problems and offering an alternative.

/*
**    BAD, NASTY, EVIL BUSY WAITNG CODE!!
**    Wait for the user to make a selection, then press start
*/
do {
    userInput = ReadControlPad (JOYMOVE + JOYBUTTON)
    switch (userInput) {
        case JOYUP
            MoveSelectionUp();
            break;
        case JOYDOWN
            MoveSelectionDown();
    }
} while (userInput != JOYSTART);
or
/*
**    BAD, NASTY, EVIL BUSY WAITNG CODE!!
**    Pause for about half a second.
*/
for (waitLoop = 0; waitLoop < ABOUT_HALF_A_SECOND; waitloop++)

Busy waiting is a bad programming practice because it consumes one of the system's most valuable resources: CPU time. It may cause a video you are streaming in to grind to a halt. In a cable television environment it may cause the picture-in-picture display the user was keeping an eye on to become jerky and out of sync. This will make your program very unpopular.

Consider the two examples of busy waiting above.

Here's a better way to do each of these:

/*
**    Wait for the user to make a selection, then press start.
**
**    Setting the wait flag to true in GetControlPad puts us into
**    the sleep queue until there's a change of control pad 
**    status, allowing lower or equal priority tasks to get time
**    slices.
*/
do {
    err = GetControlPad (kMyControlPad, true, controlPadData);
    CHECKRESULT (err, "GetControlPad");

    switch (controlPadData->cped_ButtonBits) {
        case ControlUp:
            MoveSelectionUp();
            break;
        case ControlDown:
            MoveSelectionDown();
        case ControlStart:
            polling = false;
    }
} while (polling);

or

/*
**    Wait for a half a second to go by before we proceed
*/
struct timeval delay;

delay.tv_sec     = 0;
delay.tv_usec    = 50000;
WaitTime (myTimer, &delay);            // See functions below

Wait functions used wisely eliminate busy-waiting. The 3DO Portfolio documentation, its html online version, or 411 help describe these calls. The kernel, the event broker and the audio folio all have functions for putting a process to sleep while it's awaiting a resource. Using them will measurably improve overall performance.