C# Timer for MultiThreading that can ignore ticks - c#

Regarding C# multithreading and events;
I'm trying to set up a System.Threading.Timer that triggers an AutoReset event. When the event is signalled, the code will perform a task that might take longer than the next timer tick.
In C++, when timers set autoreset events, if the event is already set, effectively nothing happens, and you just miss that particular tick. It works well, the thread can tick away setting an event that is already set, and there are no problems.
In C#, the setting of the event is queued up, either on multiple pool threads, or serially on the timer thread. I have got the timer to callback to one thread but
I cannot for the life of me remember how I did that, I found it on StackOverflow, naturally.
It seems that the callback of the timer blocks until the AutoReset event is reset.
I cannot query the event to see if it is already set.
How can I get the system to ignore this? If I am debugging one thread in the app and hold that thread up, the ticks back up and I get either thread exhaustion or database connection exhaustion, either of which kills the app off.
I have seen that I can use a System.Timers.Timer instead, but this requires a synchronizing object. I know that I have to implement a synchronizing object, but I cannot figure it out. I have found the specification of the interface, I seem to need a delegate function. On numerous responses I see people suggesting you just create a dummy synchronization object, but it's that stage that I am stumbling on.
I feel like I am chasing my tail needlessly just to get the system to ignore timer ticks. I have tried using bool flags to signal when threads are busy, but this seems like an ugly kludge. An example ISynchronizeInvoke implementation would be really helpful.
Thanks in advance for any help you can give with this.

What you're describing can't happen. AutoResetEvent.Set does not block if the event is already set, as this code clearly shows:
private System.Threading.Timer _myTimer;
private AutoResetEvent _myEvent = new AutoResetEvent(false);
private void DoIt()
{
_myTimer = new Timer(MyTimerCallback, null, 1000, 1000);
Console.WriteLine("Press Enter when done");
Console.ReadLine();
_myTimer.Dispose();
}
private void MyTimerCallback(object state)
{
_myEvent.Set();
Console.WriteLine("tick");
}
If you run that, it will output "tick" once per second until you press Enter.
That said, the problem of skipping ticks is easily handled by making a one-shot timer and re-enabling it after every tick. Like this:
private void DoIt()
{
// Timeout.Infinite makes it a one-shot timer
_myTimer = new Timer(MyTimerCallback, null, 1000, Timeout.Infinite);
// other code
}
private void MyTimerCallback(object state)
{
// do whatever processing is necessary
// and then restart the timer
_myTimer.Change(1000, Timeout.Infinite);
}
This way, the timer can't tick while a previous tick is still processing.

To ignore ticks when a previous tick handler is still running you can trivally handle this through an isRunning field:
private volatile int isRunning = 0;
public void Tick()
{
if (Interlocked.Exchange(ref isRunning, 1) == 0)
{
try
{
//do stuff
}
finally
{
isRunning = 0;
}
}
}

Related

Different behaviour of System.Timers.Timer and System.Threading.Timer

Let me start from saying that it's more a question than a problem that needs to be solved. I have the solution now and things work fine for me. But I wonder why problem occured first time.
This is the code I have right now and it works like I expect:
private void OnNewGameStarted(Game game)
{
_activeGames.Add(game);
TimeSpan delay = game.GetTimeLeft();
var timer = new Timer(delay.TotalMilliseconds) {AutoReset = false};
timer.Elapsed += (sender, args) => GameEndedCallback(game);
timer.Start();
}
private void GameEndedCallback(Game game)
{
if (_statisticsManager.RegisterGame(game))
_gamesRepository.Save(game);
_gameStatusSubscriber.GameStatusChanged(game);
}
I used to use System.Threading.Timer instead of System.Timers.Timer and sometimes timer event (GameEndedCallback method) fired and sometimes not. I couldn't find any reason why it was that way.
This is the code I used to initilize timer (other parts are the same):
TimeSpan delay = game.GetTimeLeft();
new Timer(GameEndedCallback,game,(int)delay.TotalMilliseconds,Timeout.Infinite);
}
private void GameEndedCallback(object state)
{
var game = (Game) state;
Method OnNewGameStarted is event handler and it is called after chain of methods from Fleck webserver when some certain message comes to it.
There is a post about the 3 timer types and what they do.
the main things are:
System.Timers.Timer is for multithreading work
System.Windows.Forms.Timer - from the application UI thread
System.Threading.Timer - not always thread safe!
Timeout.Infinite is The time interval between invocations of callback, in milliseconds. Specify Timeout.Infinite to disable periodic signaling. See MSDN: http://msdn.microsoft.com/en-us/library/2x96zfy7.aspx
Timeout.Infinite is a constant used to specify an infinite waiting period.
Try this to get perodic calls to the callback
new System.Threading.Timer(GameEndedCallback, game, (int)delay.TotalMilliseconds, (int)delay.TotalMilliseconds);

How to use signalling mechanism for performing intensive work (that do not overlap) with a thread and manualresetevent in C#?

I have an existing application with 1 thread running some intensive work in the background every numOfMinutesInterval. This was previously done using Thread.Sleep (sleeping for the entire interval period) but I've read that Thread.Sleep is evil and it's sloppy design, so I wanna change to a signalling mechanism. Below is the code I just wrote (using dispatcher timer from wpf, but I think in this small scenario it's the same for winforms timer as well).
The dispatcher (running in the UI thread) ticks every second, and inside the tick function it checks whether interval has passed, and if so, it will signal the manualresetevent Set(). I'm wondering if this is bad design if the intensive work extends pass the interval period? If I set the numOfMinutesInterval = 1, but the work took 1 minute and 1 second, does that mean we'll skip 1 set() call, since the tick is attempting to set() the event while work is still being done and the worker thread is not yet blocking.
Please notice also that I've set lastWorkDoneTime = DateTime.Now; after calling Set(), should I move it to the worker thread instead (calling lastWorkDoneTime = DateTime.Now; just before manualResetEvent.WaitOne();)?
If this is bad design, what should I do to change it? Thanks for reading!
//thread work done here
private void MyDoWork_ThreadStart()
{
while(FlagApplicationStillRunning == true)
{
//do the intensive work here
manualResetEvent.WaitOne();
}
}
// tick every second
private int numOfMinutesInterval = 1;
private DateTime lastWorkDoneTime = DateTime.Now;
private void DispatcherTimer_Tick(object sender, EventArgs e)
{
if((DateTime.Now - lastWorkDoneTime).Minutes > numOfMinutesInterval)
{
manualResetEvent.Set();
lastWorkDoneTime = DateTime.Now;
}
}
You could just start a task and have that perform the intensive work.
private void DispatcherTimer_Tick(object sender, EventArgs e)
{
if ((DateTime.Now - lastWorkDoneTime).Minutes > numOfMinutesInterval)
{
Task.Factory.StartNew(DoIntensiveWork());
lastWorkDoneTime = DateTime.Now;
}
}
As far as setting the lastWorkDoneTime that is up to you. If you set it in what fires off the task, you have the possibility of two or more tasks running at the same time performing the work. If you set it at the end of the function performing the work you introduce a delay that is based on how long it takes to complete the work.
I would actually look into using one of the timer objects and let that handle the timing for you instead of using the DispatcherTimer_Tick event. There is System.Timers.Timer, System.Threading.Timers, and others.
To help determine what timer option would work best for you:
Comparing the Timer Classes in the .NET Framework Class Library

Will the threadpool queue a timer's callback function, sometimes scheduling more than one thread at the same time?

In the following code TimerRecalcStatisticsElapsed should only have one instance of it running. The worker methods that this callback invokes is made to run in sequence, with a maximum of one thread running at a time.
Question Part 1:
If the timer's callback runs an a threadpool thread (as opposed to running the callback on a separate thread), is it correct to say the the threadpool might queue and defer the thread for later execution based on conditions (MaxThreads reached, threadpool internal logic)?
Question Part 2:
Assuming it's possible for one timer callback to be queued for anything but immediate execution, does that mean that any number of thread callbacks may execute concurrently?
Question Part 3
Assuming part 2 is true, does that mean the code below can ever have more than one callback operating at the same time?
The reason I'm asking is because there are several thousand instances of this class running on a multi-CPU server. I'm also seeing data corruption consistent with an out-of-order operation of // Do Work Here.
Aside
// Do work here internally works with a System.Collections.Dictionary and edits the values of y. It also removes some keys for a subsequent function that is called serially. That function is missing keys (x) that were previously present in the first call. I think this is because there is a race condition with the final statement obj.cleanupdata()
public class SystemTimerTest
{
readonly System.Timers.Timer timerRecalcStatistics;
readonly System.Diagnostics.Stopwatch stopwatchForRecalcStatistics = new System.Diagnostics.Stopwatch();
public SystemTimerTest(TimeSpan range, DataOverwriteAction action)
{
int recalculateStatisticsEveryXMillseconds = 1000;
timerRecalcStatistics = new System.Timers.Timer(recalculateStatisticsEveryXMillseconds);
timerRecalcStatistics.AutoReset = true;
timerRecalcStatistics.Elapsed += new System.Timers.ElapsedEventHandler(TimerRecalcStatisticsElapsed);
timerRecalcStatistics.Interval = recalculateStatisticsEveryXMillseconds;
timerRecalcStatistics.Enabled = true;
this.maxRange = range;
this.hashRunningTotalDB = new HashRunningTotalDB(action);
this.hashesByDate = new HashesByDate(action);
this.dataOverwriteAction = action;
}
private void TimerRecalcStatisticsElapsed(object source, System.Timers.ElapsedEventArgs e)
{
stopwatchForRecalcStatistics.Start();
Console.WriteLine("The TimerRecalcStatisticsElapsed event was raised at {0}", e.SignalTime.ToString("o"));
// DO WORK HERE
stopwatchForRecalcStatistics.Stop();
double timeBuffer = GetInterval(IntervalTypeEnum.NearestSecond, e.SignalTime) - stopwatchForRecalcStatistics.ElapsedMilliseconds;
if (timeBuffer > 0)
timerRecalcStatistics.Interval = timeBuffer;
else
timerRecalcStatistics.Interval = 1;
stopwatchForRecalcStatistics.Reset();
timerRecalcStatistics.Enabled = true;
}
}
ad 1) It is not important whether ThreadPool can defer execution of callback method, because anyway callback is not guaranteed to complete execution before another timer interval(s) elapses (thread can be suspended by thread scheduler for example, or callback might call long-running function).
ad 2) This is what MSDN says about Timer class:
If the SynchronizingObject property is null, the Elapsed event is
raised on a ThreadPool thread. If processing of the Elapsed event
lasts longer than Interval, the event might be raised again on another
ThreadPool thread. In this situation, the event handler should be
reentrant.
So the answer is YES, callback can be executing on multiple threads concurrently.
ad 3) YES. And you should either avoid using shared resources (timerRecalcStatistics, stopwatchForRecalcStatistics) in callback method, or synchronize access to these shared resources (for example with lock), or set appropriate object to Timer's SynchronizingObject property, or set AutoReset property of Timer to false (and enable timer again at the end of timer callback).
UPDATE:
I thing that Jon Skeet's answer doesn't solve your problem. Also implementing your own SynchonizingObject is IMHO more complicated than necessary (but it's hard to say without knowing whole problem). I hope this implementation should work (but I didn't tested it):
public class MySynchronizeInvoke : ISynchronizeInvoke
{
private object SyncObject = new Object();
private delegate object InvokeDelegate(Delegate method, object[] args);
public IAsyncResult BeginInvoke(Delegate method, object[] args)
{
ElapsedEventHandler handler = (ElapsedEventHandler)method;
InvokeDelegate D = Invoke;
return D.BeginInvoke(handler, args, CallbackMethod, null);
}
private void CallbackMethod(IAsyncResult ar)
{
AsyncResult result = ar as AsyncResult;
if(result != null)
((InvokeDelegate)result.AsyncDelegate).EndInvoke(ar);
}
public object EndInvoke(IAsyncResult result)
{
result.AsyncWaitHandle.WaitOne();
return null;
}
public object Invoke(Delegate method, object[] args)
{
lock(SyncObject)
{
ElapsedEventHandler handler = (ElapsedEventHandler)method;
handler(args[0], (ElapsedEventArgs)args[1]);
return null;
}
}
public bool InvokeRequired
{
get { return true; }
}
}
From the documentation on System.Timers.Timer:
If the SynchronizingObject property is null, the Elapsed event is
raised on a ThreadPool thread. If processing of the Elapsed event
lasts longer than Interval, the event might be raised again on another
ThreadPool thread. In this situation, the event handler should be
reentrant.
So to answer your questions:
Yes, it runs on a threadpool thread, and is subject to threadpool filling up and deferring like anything else. Given that the threadpool now has a maximum of hundreds of threads, this shouldn't be an issue. If it is, you have bigger problems.
Assuming that you do not set a synchronizing object or otherwise sychronize your callback, yes, multiple callback can overlap. If you give the timer a synchronizing object, it will not 'overlap' events.
The code that you provided does not synchronize it's callback in any way, and so yes it can have multiple overlapping, simultaneously executing copies of your callback. You should synchronize the method using something like a lock statement if you want all of the instances of the class to be synchronized one another, or use the SynchronizingObject of the timer if you want each individual instance of the class to only ever have one callback running at any given time.

Windows Service with AutoResetEvent

I'm currently building a Windows Service which needs to process a queue of messages that are sat in a database table. This queue could vary in length and could take anything from 5 seconds to 55 seconds to execute against all rows in the database (I'm currently using a test data set of 500,000 records)
The Windows Service is configured to run on a 30 second timer so I have tried, unsuccessfully, to ensure that when the timer delegate runs that it is not able to run again until the previous request to the method has completed successfully
I have the following code in my Windows Service OnStart method:
AutoResetEvent autoEvent = new AutoResetEvent(false);
TimerCallback timerDelegate = new TimerCallback(MessageQueue.ProcessQueue);
Timer stateTimer = new Timer(timerDelegate, autoEvent, 1000, Settings.Default.TimerInterval); // TimerInterval is 30000
autoEvent.WaitOne();
And the following code in MessageQueue.ProcessMessage:
Trace.Write("Starting ProcessQueue");
SmtpClient smtp = new SmtpClient("winprev-01");
AutoResetEvent autoEvent = (AutoResetEvent)stateObject;
foreach (MessageQueue message in AllUnprocessed)
{
switch (message.MessageType)
{
case MessageType.PlainText:
case MessageType.HTML:
SendEmail(smtp, message);
break;
case MessageType.SMS:
SendSms(message);
break;
default:
break;
}
}
autoEvent.Set();
Trace.Write("Ending ProcessQueue");
I'm using DebugView to analyse the view the Trace statements as the Service runs and I can see multiple instances of "Starting ProcessQueue" which occur every 30 seconds which is what I am trying to avoid happening
In summary: I want to call ProcessQueue and ensure that it is not executed again unless it has completed its work (this enables me to prevent the same messages in the queue being processed multiple times
I'm sure I'm missing something pretty obvious here so any help would be much appreciated :)
Dave
Why don't you have your delegate disable the timer and then re-enable it (or continue working, if timer would expire immediately) once it's through working. Provided the latency between timer firing and your delegate waking up is < 30 seconds, this should be watertight.
while (true)
{
Trace.Write("Starting ProcessQueue")
stateTimer.Enabled = false;
DateTime start = DateTime.Now;
// do the work
// check if timer should be restarted, and for how long
TimeSpan workTime = DateTime.Now - start;
double seconds = workTime.TotalSeconds;
if (seconds > 30)
{
// do the work again
continue;
}
else
{
// Restart timer to pop at the appropriate time from now
stateTimer.Interval = 30 - seconds;
stateTimer.Enabled = true;
break;
}
}
Your ProcessMessage is never checking if the resetEvent is signaled - it's just running regardless.
I post here how to fix this. However, this is not the ideal method to do what you want to do. See the bottom of my answer for that.
You have your call to 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 the overload that accepts a time out value (int or timespan), and returns a bool If the method returns true, that means it was signaled, so you can continue. If it times out (because another iteration is still running), you should just return and not try to run the code again.
If you do not use such an overload, what you are doing would be no different than wrapping the ProcessMessage method's code in a critical section (lock() on a global var, for instance) - additional threads would block, and then needlessly run.
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 isn't ideal here. You really just want to check if an instance is already running, and abort if so. ResetEvents aren't really made for that... but I wanted to address the question of using the ResetEvent anyway.
What would probably work better is to simply shut down the timer when the callback is called, and then restart it up when you are done. That way, it's impossible for that code to be re-entered while it's still running.
You absolutely would need to wrap all the code in the callback method in a try / finally though, so that you always restart the timer after.
You can trivially solve this by using a System.Threading.Timer. You make it a one-shot timer by setting its period to zero. Restart the timer in the callback. Overlapped execution of the callback is now impossible.
Since you run this so frequently, a different approach is to use a thread instead. You'll need an AutoResetEvent to signal the thread to stop in the OnStop() method. Its WaitOne() method gives you a free timer when you use the overload that takes the millisecondsTimeout argument.
Btw: note that the autoEvent.WaitOne() call in OnStart() is troublesome. It may timeout the service controller if the first email takes a long time to send. Just omit it, you got the timer started == service started.
I think you are making this a lot harder than it needs to be. Why not just create a separate thread that spins around an infinite loop calling MessageQueue.ProcessQueue and then waiting a certain amount of time before calling it again. If it is all happening on a single thread there is no way for anything to happen in parallel.
public class YourService : ServiceBase
{
private ManualResetEvent m_Stop = new ManualResetEvent(false);
protected override void OnStart(string[] args)
{
new Thread(Run).Start();
}
protected override void OnStop()
{
m_Stop.Set();
}
private void Run()
{
while (!m_Stop.WaitOne(TimeSpan.FromSeconds(30))
{
MessageQueue.ProcessMessage();
}
}
}
OnStart method
AutoResetEvent autoEvent = new AutoResetEvent(true);
while (true)
{
autoEvent.WaitOne();
Thread t = new Thread(MessageQueue.ProcessMessage);
t.Start(autoEvent);
}
What you want is a synchronization timer object. In Win32 this is known as a waitable timer (unfortunately some P/invoke is required, unless I'm mistaken).
Here's what you would do:
Create waitable timer (make sure it's auto-reset).
Set waitable timer with a period of 30 seconds.
Loop:
WaitForSingleObject(waitable timer) with infinite timeout.
Process queue.
If the processing takes more than 30s, the timer will simply remain set until you call WaitForSingleObject on it. Additionally, if the processing takes 20s for example, the timer will be signaled after 10 more seconds.

Timer Delay Degrades or becomes inconsistent over time?

I'm hoping someone can shed some light on what might be happening for me. Here's a summary of whats happening.
I have an application that does lots of "stuff". Its a pretty hefty application that does lots of number crunching using many threads. There are several timers that are used. Over a long period of time, the timers stop consistently invoking the elapsed handler.
For instance: I have a timer set to elapse every second. After a period of hours the timer starts randomly triggering late. If I do not restart the application the performance just degrades and the timers fire later and later eventually turning into 3 or 4 seconds, forcing me to restart the application. I have not been able to identify any leaks. CPU usage does not go up, memory does not go up, and the server is no where near being maxed out. Can anyone give me some ideas as to what may be causing this?
private void Timer_Elapsed(object source, ElapsedEventArgs e)
{
if (seconds > 0)
{
seconds--;
timer.Start();
}
}
Is it possible you're exhausting the thread pool? Most timers invoke the handler using a threadpool thread. If all threadpool threads are in use, it will just get queued until one is available.
If that's the case switch some of your processing to use your own threads, not threadpool threads.
To test if you're exhausting the thread pool start up a background thread that periodically (a few times a second) checks ThreadPool.GetAvailableThreads and logs a message when the available is small (even if it's never actually zero when you check, if it sometimes approaches zero then it's likely this is the problem).
The size of the pool can be changed with ThreadPool.SetMaxThreads although that may not be the best solution. If you're using threadpool threads for longer running tasks, stop it. For long-running tasks use your own threads.
the timer class you use is really important
http://msdn.microsoft.com/en-us/magazine/cc164015.aspx
but I don't think the problem is the timer itself,
for instance try making an application using the same timer class
that ONLY writes the current DateTime to a log file
and leave it running for an extremely long period of time, you'll see that there's no such a 3/4 seconds delay
review your timer code and check that no shared resources are being accessed at the same time,
maybe the Timer is OK, but there's a bottleneck in the event handler function or in "something" that function uses
Sounds like maybe it's not really the same timer, and so the resources being "leaked" here are GDI handles.
Possible workaround:
DateTime mayContinue = DateTime.MinValue;
bool blockingUi = false;
private void Timer_Elapsed(object source, ElapsedEventArgs e)
{
if( blockingUi )
{
if( DateTime.Now < mayContinue )
{
// Notify time remaining
// Update the UI with a BeginInvoke
}
else
{
blockingUi = false;
// Notify ready
// Update the UI with a BeginInvoke
}
}
}
private void BlockUi()
{
mayContinue = DateTime.Now.AddSeconds(30);
blockingUi = true;
}

Categories

Resources