Tuesday, August 12, 2008

Sleep

When I first started programming, I thought "Sleep" to be one of the most useless calls I could make. No, I'm not talking about personal habits, I'm talking about the Sleep() function.


using System.Threading;
Thread.Sleep(int milliSeconds)

We find this little "do nothing" function in C, C++, C#, VB, VB.Net, WScipt, and similar functions in other languages. And, I have since come to understand how useful and confusing "doing nothing" can be. So, let's take a look at it; I'll be focusing on the C# Sleep() function.

Sleep() simply suspends the execution of your thread for a specific period of time. It relinquishes the remainder of its time-slice and becomes "unrunnable" for a period of time. If the time period is zero, it relinquish its time-slice only if another thread is ready and waiting to run. If there are no waiting threads, and the time span is zero, the calling thread remains ready to run and therefore returns from Sleep() immediately.

So, Sleep() is useful for delaying a thread, or for getting a thread out of the way of other threads. Let's say a user enters a password incorrectly, a delay at this point is useful to help dissuade a rapid fire brute force attack on your password input algorithm. Keep in mind that Sleep() also takes away the thread's responsiveness. So, delaying operations should only be implemented with Sleep() if you can tolerate or mitigate the total lack of responsiveness from the sleeping thread.

Sleep() is also useful for making a thread behave nicely by not hogging the CPU. The Operating System will preempt threads for you and let other threads run. But you may still see your thread taking up way too much processor resources and not allowing other threads enough time to run. A Sleep() for some very short interval could be useful in improving overall application responsiveness. Here again, calling Sleep(0) on a thread that is very busy processing messages is about useless because each call to the message queue already allows other waiting threads to run.

You can use Sleep() for very simple timed delays. A pattern where there is a producer and several consumers might use a Sleep() to throttle the producer to let the consumers keep up or catch up. That is, the producer might fill a queue and then stop and Sleep() when the queue gets too full. The amount of time the producer thread sleeps determine how much the consumers have a chance to process. But even so, a more robust implementation would have the producer "wait" for space available on the queue or even the queue reaching a "low water mark", rather than blindly sleeping.

The single most often misuse of Sleep() in C# is when a thread that has created a window then calls Sleep(). Threads that create windows, whether directly or indirectly, must remain awake to process messages. When a thread sleeps, it cannot process those messages and the application appears to hang. The C/C++ documentation for SleepEx() and Sleep() in fact warn that should a thread sleep indefinitely, when it should be processing messages, then the system will deadlock because message broadcasts are sent to all windows in the system.

We are not discussing C/C++ and we certainly are not going to sleep indefinitely. So, C# should keep us out of such a catastrophic situation, but the C# programmer must still avoid putting "GUI" threads to sleep to avoid hanging up his application. The C# documentation for Sleep() simply says "This method does not perform standard COM and SendMessage pumping". This hardly suggests how ugly the application behavior can be if you use Sleep() on your GUI thread. In short, just keep your Sleep() off of the GUI threads, and keep your COM and DDE calls (unless absolutely sure there is no GUI involved) on the GUI threads.

What are the alternatives to calling Sleep() on a GUI thread? First, and foremost, your best alternative is a good architecture starting out. GUI threads never "need" to sleep because they should normally be waiting for messages. If a GUI thread is so busy that it can't service the messages as they arrive, the GUI should offload the work to a separate thread. But, if your GUI is so busy, it's probably not going to sleep anyway. If a GUI needs to wait for something to happen that won't occur on its message/event loop, it should delegate that wait to a thread as well, and then use state variables to modify its behavior until the desired event occurs.

For example, reading from a network could wait for a very long time. A GUI would act like it's hung if it got stuck at a network read for any length of time. The same goes for reading streams. Often a stream may resolve to a network resource. Or, if you are reading a lot of data from a file, the application will similarly appear hung. By delegating the operation to a separate thread, the GUI is free to respond to other events. Its tempting at this point for the GUI to Sleep(), but don't do it. Instead, set a state variable that indicates an operation is in progress and prevent your other dependant GUI operations from proceeding until the operation finishes. Better yet, try to eliminate the GUI dependancy on the completion of the read altogether. Architect your application with threads well chosen for the task, especially if you must wait for various kinds of system events.

Another alternative to Sleep() is a "Timer" function (see my articles on timers). With a timer function, a thread simply schedules a time when it will get back to the item its waiting for. In the meantime, the GUI continues to receive messages and events. In fact, the timer expiration is just an event which you write a handler for.

If your thread must wait for something, your best performance will be achieved through the proper use of "Wait" type calls. WaitOne() and WaitAny() on an appropriate "WaitHandle" is always better performance wise than Sleep() because your thread waits only as long as it takes for the event to fire and the context switch to occur. Furthermore, there is no risk of the thread returning earlier than the event (unless you provide a timeout to "Wait").

How accurate is Sleep()? The Sleep time interval is specified to the millisecond. But Sleep() time expiration is serviced by the Operating System based upon its "tick" size. CPU ticks occur at a constant rate larger than a 1 millisecond granularity. So, threads will not wake at exactly the time span specified due to CPU tick granularity and scheduling priorities. They wake at their first scheduled opportunity after becoming "ready to run". They become ready to run at a time determined by how divisible the sleep time interval is by the CPU tick value. Sleeping threads become runnable on CPU Tick intervals. You can control the "tick" size (and thus the accuracy of Sleep) in C/C++ with timeGetDevCaps, timeBeginPeriod and timeEndPeriod.

By the way, while we are on the topic of C/C++, the call to SleepEx() is worth mentioning. SleepEx() is an alertable sleep function that awakes prior the elaspe of the time period when the same thread's I/O completion callback is called or when an APC function is called. The lines between "Sleep" and "Wait" begin to blur with this function.

In summary, use Sleep() as the "poor man's" Wait() function. Setting up a WaitHandle, synchronizing correctly, and handling timeouts with a "Wait" can be complex. Certainly, the "Wait" type calls would provide much lower latency, but if a few seconds of latency does not adversely affect your application, you don't need that added complexity. Sleep() is simple, use it simply. Never sleep on the GUI, or on the job, the consequences are not pretty.

That about wraps it up. There is no code today. Enjoy.

No comments: