How to handle multiple asynchronous requests with a wait loop

This document describes how to handle multiple asynchronous requests with a wait loop.

A user thread which requires asynchronous services from more than one asynchronous service provider uses a wait loop.

The allows a thread to issue as many request as are necessary and to handle their completion. This construction forms the heart of almost all programs that run under Symbian platform.

A typical program:

  • waits for any request to complete by waiting on the thread’s request semaphore.

  • scans in turn through the asynchronous service providers for which a request is known to have been issued and tests the relevant TRequestStatus for completion; this is identified by a value other than KRequestPending.

  • when the first such completed request has been identified, handles the completed request, possibly by issuing a further request to an asynchronous service provider.

  • goes back to the top of the wait loop and waits again.

As an example, a terminal emulator must work with multiple requests simultaneously, to deal with:

  • key presses and user input in general, to control the action of the program and put characters on the emulated terminal screen and/or send them to the remote host

  • received data and to put characters on the emulated terminal screen or perform some control function.

  • the completion of any transmit operation that was in progress; if successful, there may be more data to transmit; if unsuccessful, some recovery action may be necessary

Typical wait loop protocol

The typical protocol of a wait loop is:

  • The initialization phase which issues the first asynchronous requests.

  • Entry into the main loop which waits for any of these requests to complete and then handles the completion of one of them.

  • Detection of conditions which imply termination of the program. Typically, one of the request completion handlers sets appropriate flags and the wait loop terminates.

  • Cleanup and final termination.

while (!finished())
    wait for one or more requests to complete
    decide which request completed, and handle it

Note that only one request should be handled per iteration of the loop. As part of the request completion handling process, the request may be re-issued, or new requests issued or existing ones cancelled. If the request cannot be identified, then the thread’s request semaphore has been signalled invalidly; this is indicative of a programming error, a condition is known as a stray signal - the wait loop should raise a panic.

Multiple outstanding requests

In the case of a terminal emulator which works with multiple outstanding requests, it must be able to service whichever request completes and must be able to re-issue a request, if necessary. For example, when one key has been processed, a request for the next key must be issued.

In the following example:

  • Call Initialize() to initialize the emulator.

  • Implement while() to handle events.

  • Call the function User::WaitForAnyRequest() to wait for any request to complete instead of waiting for a specific request to complete.

  • Identify the particular request that completed by checking the request status objects for a value not equal to KRequestPending.

class TerminalEmulator
    void MainLoop(); // main loop
    void Initialize(); // initialize
    void Terminate(); // clean up and terminate
    TBool IsFinished(); // whether finished
    // request status objects
    TRequestStatus iKeyPressed; // whether key pressed
    ...                         // ...etc for other request status
    // handler functions
    void HandleKeyPressed();    // handle key pressed
    ...                         // ... etc other handlers
void TerminalEmulator::MainLoop()
    Initialize();         // Initialize emulator
    while (!IsFinished()) // Handle events until finished
        // wait for any request to complete

        // identify and handle the completed request
        if (iKeyPressed!=KRequestPending)
        else if (iReceiveCompleted!=KRequestPending)
            else if (iTransmitCompleted!=KRequestPending)
                    // something we weren’t expecting
                    // panic !


  • The request status is set by the service provider to KRequestPending when a request is issued. When the request is complete, the service provider uses an operating system call to set the request status value to some other value — usually a standard error code — and then to wake up the thread that requested the service, causing its WaitForAnyRequest() to complete.