We all had to use Thread.Sleep at one point or another to wait on an event to happen, or to satisfy a configuration setting during cyclic calculations or a processing. But is your worker thread sleeping too much? Does it feel sometimes that your code sleeps in the wrong time
increments when it shouldn’t be? Making your “Multi-Threaded” C# software not as responsive as you hoped it would be?
One possible reaosn that can cause this to happen is the improper usage of Thread.Sleep calls. The problem is that sleeping for a long interval can sometimes lead to less responsive applications. For example, suppose you have a worker thread which wakes up every 1 minute, processes some data, then goes back to sleep. Here is how its event loop might look like:
int
cycleSleepTime=60000;
// or load from config
volatile
bool
_bStop=
false
;
// Worker Thread Processing loop
while
(!_bStop)
{
// Process Data Here
// ...
// Sleep for a minute
System.Threading.
Thread
.Sleep(cycleSleepTime);
}
If you wanted to stop the worker thread from the main thread, you’d set the volatile member _bStop to true which puts a condition that causes the processing loop to exit the next time it executes:
// From
Main
Thread: Request the worker thread to stop
_bStop=true;
What’s the problem with the above implementation? Well, suppose that cycleSleepTime was a configurable variable, and your user decided to increase it to say, every 10 minutes. Since the worker thread’s event loop processes every thing, including stop requests only when it wakes up, it might take it up to 10 minutes before it honors the main thread’s request to stop processing. Suppose you displayed the processing status in a multi-threaded GUI application. Waiting 10 minutes to stop something from the GUI before it actually stops is a long time, and would render your “multi-threaded” application sloppy and unresponsive, even though you are using threads and all the good stuff.
So what’s the alternative? The answer is to separate processing important requests (like the stop request) from the rest of the worker’s thread loop. One way to achieve that is to sleep intermittently for small periods of time to stay responsive to important messages and events.
The following method can be used in place of the Thread.Sleep:
public
void SleepIntermittently(int totalTime)
{
int sleptTime = 0;
int intermittentSleepIncrement = 10;
// Wake up every 10 milli-seconds too check if we need
// to stop or not
while (!_bStop && sleptTime < totalTime)
{
Thread.Sleep(intermittentSleepIncrement);
sleptTime += intermittentSleepIncrement;
}
}
Now in the worker’s thread, all we have to do is make the following small change:
int
cycleSleepTime=60000; // or load from config
volatile
bool _bStop=false;
// Worker Thread Processing loop
while
(!_bStop)
{
// Process Data Here
// ...
// Sleep for a minute
SleepIntermittently(cycleSleepTime);
}
Now when the main thread requests to stop the worker’s thread, the response can come back within 10 milliseconds (a big performance gain compared to up to 10 minutes before), no matter what the
cycleSleepTime
happens to be, and the user can change it freely from the configuration file without affecting how the application responds to the user’s important commands. Definitely a better design!