Your ProcessMessage never checks if there is a resetEvent signal - it just works independently.
I am writing here how to fix it. However, this is not an ideal way to do what you want to do. See the bottom of my answer.
You are calling autoEvent.WaitOne() in the wrong place; it should be at the beginning of the ProcessMessage method.
AutoResetEvent autoEvent = (AutoResetEvent)stateObject; autoEvent.WaitOne(); Trace.Write("Starting ProcessQueue"); SmtpClient smtp = new SmtpClient("winprev-01"); foreach (MessageQueue message in AllUnprocessed){
You should also use an overload that takes a timeout value (int or timespan) and returns a bool If the method returns true , it means that it has been signaled, so you can continue. If time runs out (because another iteration is still running), you should just go back and not try to run the code again.
If you do not use such overloading, then what you are doing is no different from transferring the code of the ProcessMessage method in the critical section ( lock() on the global var, for example) - additional threads block and then it is useless to work.
AutoResetEvent autoEvent = (AutoResetEvent)stateObject; //wait just one ms to see if it gets signaled; returns false if not if(autoEvent.WaitOne(1)){ Trace.Write("Starting ProcessQueue"); SmtpClient smtp = new SmtpClient("winprev-01"); foreach (MessageQueue message in AllUnprocessed){
Note that actually a *ResetEvent is not ideal here. You really want to check if the instance is running, and abort it, if so. resetEvent not really created for this ... but I still wanted to resolve the issue of using ResetEvent.
What would be better to work is to simply turn off the timer when calling callback, and then restart it when you are done. Thus, it is not possible for this code to be re-entered while it is running.
You absolutely will need to wrap all the code in the callback method in try / finally , though, so that you always restart the timer after.