Thread synchronization with the System.Timers.Timer class (part one)

by Scosby Sunday, January 4, 2009

Part one of this series will focus on what you should do if you run across a System.Timers.Timer component, especially if you are performing maintenance on the code base.

If you need your program to perform some task repeatedly, you’ve probably used one of the three Timers in the .NET framework to do this. I will focus on the System.Timers.Timer class, which is considered a “server” timer.  The other two types are the System.Threading.Timer class and the System.Windows.Forms.Timer class. I will briefly explain the three timers and their usefulness, but you should read about them on MSDN if you want further details.

·         The System.Threading.Timer class is a lightweight multithreaded timer class. It does not raise events but offers the basic functionality of the other two timer classes.

·         The System.Windows.Forms.Timer class is designed for Windows Forms applications that have a UI to display. It is single-threaded, has a limited accuracy of 55 milliseconds, and requires a UI message pump.

·         The System.Timers.Timer class is a server-based timer designed for use with worker threads in a multi-threaded environment.

Which timer should I use? The answer to that question is the ubiquitous: it depends. Seriously, it truly depends on what your expectations are and the type of program you are building. I think we can all agree that single thread applications are easier to program, but the time of parallel computing is fast approaching and as developers, we need to learn how to synchronize threads. I will expand on this topic in part  2 of this series, so let’s table this question in the meantime.

For part 1 of this series, let’s assume you run across a Windows Service in your code base. It is supposed to perform some task at a given interval. To do this it is using the System.Timers.Timer class, and in the Elapsed event handler the Timer is stopped to try and prevent additional events from being raised. Let’s look at what is wrong with this implementation and how to fix it if we can’t change the implementation (which part 2 of this series will explore).

There are two issues regarding this approach. First, if you have a timer in your application, it is very likely that your response to the timer’s interval is going to take longer than it will for the interval time span to elapse again. In other words, your callback/event will take longer to execute than it will for the timer to fire off the same callback/event again. Which means you will have overlapping events. Second, I have seen code try to stop the System.Timers.Timer class to prevent situation one, but this technique has an unintended consequence. The Stop() method toggles the Enabled property. By reflecting the class and looking at the Enabled property the problem with this technique becomes obvious. Here is the snippet:

if (!value)
        {
            if (this.timer != null)
            {
                this.cookie = null;
                this.timer.Dispose();
                this.timer = null;
            }
            this.enabled = value;
        }

Notice how the Enabled property disposes the timer (based on ‘value’ which represents the Boolean you’ve set the property to), which could let the timer continue to raise events after you THOUGHT you stopped it (even though the code “nulls” the internal timer object). What that means is out of the scope of this post, but it has to do with how the Garbage Collector finalizes objects for collection. See Jeffery Richter’s book, CLR via C# chapter 20 for a detailed discussion of how this works.

 This is why MSDN recommends you design your event handler to be “reentrant” using the Interlocked class’s CompareExchange() method instead of simply stopping the timer and crossing your fingers. Assuming you only wish for one elapsed event to be handled at any given time, using this technique is appropriate. Here is a code snippet  simplifying the MSDN example of reentrancy avoidance above:

private void m_Timer_Elapsed(object sender, ElapsedEventArgs e)       

{           

if (System.Threading.Interlocked.CompareExchange(ref m_synchPoint, 1, 0) == 0)           

{               

//safe to perform event - no other thread is running the event               

//... implement processing ...                

//Be sure to release control of the syncPoint from this thread when done               

m_syncPoint = 0;           

}            

else           

{               

//another thread is already running the event           

}       

}

In this example, we have a private member field, ‘m_syncPoint’, that is of type Int32. We store a 1 in this field if an event is being processed or a 0 if no event is being processed. The Interlocked.CompareExchange method handles the Thread Synchronization to ensure only 1 thread can change the value when it attempts to process the event handler. Note, be sure to release control of the syncPoint when your processing finishes.In summary, if you are doing some maintence work on a code base and run across a System.Timers.Timer component. I would advise you to add some tracing and verify you are getting the expected behavior. Simply stopping the timer does not guarantee you a thread-safe implementation according to MSDN and my experience with Windows Services! The addition of the Interlocked.CompareExchange method and a private member field, which is really 1 line of code outside of the if/else statement, allows you to easily guarantee a single instance of the event handler is processed at a time.Thread synchronization is an important design consideration when using any timer class, other than System.Windows.Forms.Timers, since you are working with a multi-threaded implementation whether you like it or not.  Part two will expand on this first post to show you how it’s possible to get a better implementation by using  the System.Threading.Timer class, with fewer headaches from the Interlocked class.

Tags: , ,

Technology | Programming

blog comments powered by Disqus