t e m p o r a l 
 d o o r w a y 

Pausing And / Or Stopping A Loop Without Using Threads

 

Introduction

It seems to be a frequent problem that a developer wants to offer the ability to pause and restart a loop. Sometimes, this can be handled by placing processing in a thread. Other times, it would be preferable to avoid that complexity. This article shows how you can do this with a minimal use of system resources when paused.

What You Need

This technique uses three controls (StartButton,StopButton, and PauseCheckbox). These are the event handlers for the start button and the stop button. There is no handler for the checkbox.

void __fastcall TMainForm::StartButtonClick(TObject *Sender)
{
   Screen->Cursor = crHourGlass;

   StartButton->Enabled = false;

   PauseCheckBox->Enabled = true;
   PauseCheckBox->Checked = false;

   StopButton->Enabled = true;

   while (Whatever() && !StopPending)
   {
         Application->ProcessMessages(); // Note - a WM_CLOSE can kill this loop right here

         while (PauseCheckBox->Checked && !StopPending)
         {
            WaitMessage(); // Waits for any message to appear in the queue, including a click on the check box
            Application->ProcessMessages(); // Note - a WM_CLOSE can kill this loop right here
         };
   };

   StopPending = false;

   PauseCheckBox->Enabled = false;
   PauseCheckBox->Checked = false;

   StopButton->Enabled = false;

   Screen->Cursor = crDefault;

   StartButton->Enabled = true;
}
//---------------------------------------------------------------------------
void __fastcall TMainForm::StopButtonClick(TObject *Sender)
{
   StopPending = true;   
}
//---------------------------------------------------------------------------

How It Works

These function use the Windows API function WaitMessage to allow the function to wait for the click on the pause check box or the stop button. Since WaitMessage does not process the message, it then lets the application do so.

One approach frequently cited for this problem is to loop on Application->ProcessMessages. Unfortunately, this does not conserve system resources during the pause. If there are no messages in the queue, it simply returns control to the main thread.

What Needs To Be Done

This logic doesn't completely handle the issue of the user trying to close the app. You could simply have the form OnCloseQuery return StartButton->Enabled (if it is enabled we aren't in the loop), which would prevent closing without having first hit Stop.

Copyright © 2004 by Mark Cashman (unless otherwise indicated), All Rights Reserved