I have a windows service (.NET 4) that periodically processes a queue, for example every 15 minutes. I use a System.Threading.Timer which is set when the service starts to fire a callback every X milliseconds. Typically each run takes seconds and never collides, but what if I could not assume that - then I want the next run to exit at once if processing is in progress.
This is easily solved with lock, volatile bool or a monitor, but what is actually the appropriate to use in this scenario, or simply the preferred option in general?
I've found other posts that answers almost this scenario (like Volatile vs. Interlocked vs. lock) but need some advice on extending this to a Timer example with immediate exit.
You don't need any locks for this, you should just reschedule next timer execution from within the timer delegate. That should ensure 100% no overlaps.
At the end of timer's event handler call timer.Change(nextRunInMilliseconds, Timeout.Infinite), that way the timer will fire only once, after nextRunInMilliseconds.
Example:
//Object that holds timer state, and possible additional data
private class TimerState
{
public Timer Timer { get; set; }
public bool Stop { get; set; }
}
public void Run()
{
var timerState = new TimerState();
//Create the timer but don't start it
timerState.Timer = new Timer(OnTimer, timerState, Timeout.Infinite, Timeout.Infinite);
//Start the timer
timerState.Timer.Change(1000, Timeout.Infinite);
}
public void OnTimer(object state)
{
var timerState = (TimerState) state;
try
{
//Do work
}
finally
{
//Reschedule timer
if (!timerState.Stop)
timerState.Timer.Change(1000, Timeout.Infinite);
}
}
Well, any of them will do the job. Monitor is usually pretty simple to use via lock, but you can't use lock in this case because you need to specify a zero timeout; as such, the simplest approach is probably a CompareExchange:
private int isRunning;
...
if(Interlocked.CompareExchange(ref isRunning, 1, 0) == 0) {
try {
// your work
} finally {
Interlocked.Exchange(ref isRunning, 0);
}
}
to do the same with Monitor is:
private readonly object syncLock = new object();
...
bool lockTaken = false;
try {
Monitor.TryEnter(syncLock, 0, ref lockTaken);
if (lockTaken) {
// your work
}
} finally {
if(lockTaken) Monitor.Exit(syncLock);
}
I think, that if you find that you need to synchronize timer delegate - you are doing it wrong, and Timer is probably not the class you want to use. Imho its better to :
1) either keep the Timer, but increase the interval value to the point, where its safe to assume, that there will be no issues with threading,
2) or remove Timer and use simple Thread instead. You know, something like:
var t = new Thread();
t.Start(() =>
{
while (!_stopEvent.WaitOne(100))
{
..........
}
});
Related
I found this
Run async method regularly with specified interval
which does half of what I want, but at the same time I want to be able to stop the loop whenever I want and then resume it as well. However while it's stopped, I don't want the infinite loop to keep running where the body gets skipped through a flag.
Basically I don't want this
while (true) {
if (!paused) {
// run work
}
// task delay
}
because then the while loop still runs.
How can I set it so that while its paused, nothing executes?
How can I set it so that while its paused, nothing executes?
That's hard to answer: if you define "pause" as: the object state remains valid while the loop doesn't use any resources then you'll have to stop and restart it (the loop).
All other timers, including Thread.Sleep, Task.Delays etc. will put your thread in idle/suspended mode.
If that's not sufficient for your needs, you'll need to actually stop the "infinite" loop.
It will free up thread related resources as well.
More info about sleep:
Thread.Sleep
More about sleep
You could use System.Threading.Timer and dispose of it while it is not in use and re-create it when you are ready to "resume". These timers are light weight so creating and destroying them on demand is not a problem.
private System.Threading.Timer _timer;
public void StartResumeTimer()
{
if(_timer == null)
_timer = new System.Threading.Timer(async (e) => await DoWorkAsync(e), null, 0, 5000);
}
public void StopPauseTimer()
{
_timer?.Dispose();
_timer = null;
}
public async Task DoWorkAsync(object state)
{
await Task.Delay(500); // do some work here, Task.Delay is just something to make the code compile
}
If you are really adverse to timers and want it to look like a while loop, then you can use TaskCompletionSource<T>:
private TaskCompletionSource<bool> _paused = null;
public async Task DoWork()
{
while (true)
{
if (_paused != null)
{
await _paused.Task;
_paused = null;
}
//run work
await Task.Delay(100);
}
}
public void Pause()
{
_paused = _paused ?? new TaskCompletionSource<bool>();
}
public void UnPause()
{
_paused?.SetResult(true);
}
I have a requirement for a timer that has the following behaviour:
Millisecond accuracy
I want the tick event handler to only be called once the current tick handler has completed (much like the winforms timer)
I want exceptions on the main UI thread not to be swallowed up by the thread timer so this requires Invoke/Send instead of BeginInvoke/Post
I've played around with CreateTimerQueueTimer and had some success but at the same time had problems with code reentrance and/or locks when deleting the timer.
I decided to create my own timer so that I could get a better idea of what is going on under the hood so that I can fix the locking and reentrance problems. My code seems to work fine leading me to believe that I may as well use it. Does it look sound?
I've put in a check if the timer is deleted to make sure that the deletion is complete before the timer can be created again. Does that look ok?
Note: I should say that I call timeBeginPeriod(1) and timeEndPeriod(1) inorder to achieve the millisecond accuracy.
(The following code is converted from vb.net to c#, so apologies for any missed mess-ups}
ETA: I've found a problem with it. If the timer is running at an interval of 1 millisecond, and I call, say, Change(300), it locks up # while (this.DeleteRequest). This
must be because the TimerLoop is in the this.CallbackDelegate.Invoke(null) call.
public class MyTimer : IDisposable
{
private System.Threading.TimerCallback CallbackDelegate;
private bool DeleteRequest;
private System.Threading.Thread MainThread;
public MyTimer(System.Threading.TimerCallback callBack)
{
this.CallbackDelegate = callBack;
}
public void Create(int interval)
{
while (this.DeleteRequest) {
System.Threading.Thread.Sleep(0);
}
if (this.MainThread != null) {
throw new Exception("");
}
this.MainThread = new System.Threading.Thread(TimerLoop);
// Make sure the thread is automatically killed when the app is closed.
this.MainThread.IsBackground = true;
this.MainThread.Start(interval);
}
public void Change(int interval)
{
// A lock required here?
if (!this.IsRunning()) {
throw new Exception("");
}
this.Delete();
this.Create(interval);
}
public void Delete()
{
this.DeleteRequest = true;
}
public bool IsRunning()
{
return (this.MainThread != null) && this.MainThread.IsAlive;
}
private void TimerLoop(object args)
{
int interval = (int)args;
Stopwatch sw = new Stopwatch();
sw.Start();
do {
if (this.DeleteRequest) {
this.MainThread = null;
this.DeleteRequest = false;
return;
}
long t1 = sw.ElapsedMilliseconds;
// I want to wait until the operation completes, so I use Invoke.
this.CallbackDelegate.Invoke(null);
if (this.DeleteRequest) {
this.MainThread = null;
this.DeleteRequest = false;
return;
}
long t2 = sw.ElapsedMilliseconds;
int temp = Convert.ToInt32(Math.Max(interval - (t2 - t1), 0));
sw.Reset();
if (temp > 0) {
System.Threading.Thread.Sleep(temp);
}
sw.Start();
} while (true);
}
// The dispose method calls this.Delete()
}
I would recommend using p/Invoke and using the timers from Win32's Timer Queues:
http://msdn.microsoft.com/en-us/library/ms686796(v=vs.85).aspx
One should be mindful that the managed CLR environment has a lot of non-determinism built into it, garbage collection, for instance. Just because your timer is has a period of 1 millisecond doesn't mean that that is necessarily what happens.
Also, the documentation doesn't mention it, but the callback invoked by the timer must be pinned in memory and not garbage collectable, via a GCHandle or other construct. When a timer (or timers, if you kill off a timer queue), the callback will be executed one last time. Not sure whether that happens by the internal wait expiring, or by signalling the internal event handle.
Execution of DeleteTimerQueueTimer() and DeleteTimerQueueEx() can be made synchronous, so they won't return until all timers have signalled and invoked their last callback, but doing that would be suboptimal.
If you don't pin the callbacks and prevent them from being garbage-collected, things will go swimmingly...most of the time. You'll encounter random exceptions.
Also, the callback should be smart enough to bail out if the timer is being deleted, lest it make reference to something that's already GC'd.
μTimer would be a better example!
You can find it here # https://stackoverflow.com/questions/15725711/obtaining-microsecond-precision-using-net-without-platform-invoke?noredirect=1#comment22341931_15725711
It provides accurate wait times down to 1µs and possibly lower depending on your NIC!
Let me know if you need anything else!
While working on a large project I realized I was making a lot of calls to be scheduled in the future. Since these were fairly light-weight, I thought it might be better to use a separate scheduler.
ThreadPool.QueueUserWorkItem (() =>
{
Thread.Sleep (5000);
Foo (); // Call is to be executed after sometime
});
So I created a separate scheduler class that runs on its own thread and executes these events. I have 2 functions that access a shared queue from separate threads. I'd use a lock, but since one of the threads needs to sleep-wait, I wasn't sure how to release the lock.
class Scheduler
{
SortedDictionary <DateTime, Action> _queue;
EventWaitHandle _sync;
// Runs on its own thread
void Run ()
{
while (true)
{
// Calculate time till first event
// If queue empty, use pre-defined value
TimeSpan timeDiff = _queue.First().Key - DateTime.Now;
// Execute action if in the next 100ms
if (timeDiff < 100ms)
...
// Wait on event handle for time
else
_sync.WaitOne (timeDiff);
}
}
// Can be called by any thread
void ScheduleEvent (Action action, DataTime time)
{
_queue.Add (time, action);
// Signal thread to wake up and check again
_sync.Set ();
}
}
The trouble is, I'm not sure how to synchronize access to the queue between the 2 functions. I can't use a monitor or mutex, because Run() will sleep-wait, thus causing a deadlock. What is the right synchronization mechanism to use here? (If there a mechanism to atomically start the sleep-wait process and immediately release the lock, that might solve my problem)
How can I verify there is no race-condition?
Is this a variation of the producer consumer problem, or is there a more relevant synchronization problem-description?
While this is somewhat geared towards C#, I'd be happy to hear a general solution to this. Thanks!
OK, take 2 with Monitor/Pulse.
void Run ()
{
while (true)
{
Action doit = null;
lock(_queueLock)
{
while (_queue.IsEmpty())
Monitor.Wait(_queueLock);
TimeSpan timeDiff = _queue.First().Key - DateTime.Now;
if (timeDiff < 100ms)
doit = _queue.Dequeue();
}
if (doit != null)
; //execute doit
else
_sync.WaitOne (timeDiff);
}
}
void ScheduleEvent (Action action, DataTime time)
{
lock (_queueLock)
{
_queue.Add(time, action);
// Signal thread to wake up and check again
_sync.Set ();
if (_queue.Count == 1)
Monitor.Pulse(_queuLock);
}
}
The problem is easily solved, make sure the WaitOne is outside the lock.
//untested
while (true)
{
Action doit = null;
// Calculate time till first event
// If queue empty, use pre-defined value
lock(_queueLock)
{
TimeSpan timeDiff = _queue.First().Key - DateTime.Now;
if (timeDiff < 100ms)
doit = _queue.Dequeue();
}
if (doit != null)
// execute it
else
_sync.WaitOne (timeDiff);
}
_queueLock is a private helper object.
Since your goal is to schedule a task after a particular period of time, why not just use the System.Threading.Timer? It doesn't require dedicating a thread for the scheduling and takes advantage of the OS to wake up a worker thread. I've used this (removed some comments and other timer service functionality):
public sealed class TimerService : ITimerService
{
public void WhenElapsed(TimeSpan duration, Action callback)
{
if (callback == null) throw new ArgumentNullException("callback");
//Set up state to allow cleanup after timer completes
var timerState = new TimerState(callback);
var timer = new Timer(OnTimerElapsed, timerState, Timeout.Infinite, Timeout.Infinite);
timerState.Timer = timer;
//Start the timer
timer.Change((int) duration.TotalMilliseconds, Timeout.Infinite);
}
private void OnTimerElapsed(Object state)
{
var timerState = (TimerState)state;
timerState.Timer.Dispose();
timerState.Callback();
}
private class TimerState
{
public Timer Timer { get; set; }
public Action Callback { get; private set; }
public TimerState(Action callback)
{
Callback = callback;
}
}
}
The monitores were created for this kind of situation, simple problems that can cost mutch for the application, i present my solution to this very simple and if u want to make a shutdown easy to implement:
void Run()
{
while(true)
lock(this)
{
int timeToSleep = getTimeToSleep() //check your list and return a value
if(timeToSleep <= 100)
action...
else
{
int currTime = Datetime.Now;
int currCount = yourList.Count;
try{
do{
Monitor.Wait(this,timeToSleep);
if(Datetime.now >= (tomeToSleep + currtime))
break; //time passed
else if(yourList.Count != currCount)
break; //new element added go check it
currTime = Datetime.Now;
}while(true);
}
}catch(ThreadInterruptedException e)
{
//do cleanup code or check for shutdown notification
}
}
}
}
void ScheduleEvent (Action action, DataTime time)
{
lock(this)
{
yourlist.add ...
Monitor.Pulse(this);
}
}
I have a Windows Service application which uses a Threading.Timer and a TimerCallback to do some processing at particular intervals. I need to lock down this processing code to only 1 thread at a time.
So for example, the service is started and the first callback is triggered and a thread is started and begins processing. This works ok as long as the processing is completed before the next callback. So say for instance the processing is taking a little longer than usual and the TimerCallback is triggered again whilst another thread is processing, I need to make that thread wait until the other thread is done.
Here's a sample of my code:
static Timer timer;
static object locker = new object();
public void Start()
{
var callback = new TimerCallback(DoSomething);
timer = new Timer(callback, null, 0, 10000);
}
public void DoSomething()
{
lock(locker)
{
// my processing code
}
}
Is this a safe way of doing this? What happens if the queue gets quite substantial? Is there a better option?
If it's OK for you to have the events fire with a constant interval between them (as opposed to the current code which fires them at a constant interval) then you can start the timer without a period, and each time queue up a new callback, e.g.
static Timer timer;
public void Start()
{
var callback = new TimerCallback(DoSomething);
timer = new Timer(callback, null, 0, Timeout.Infinite);
}
public void DoSomething()
{
try
{
// my processing code
}
finally
{
timer.Change(10000, Timeout.Infinite);
}
}
This code tells the newly created timer to fire immediately, once only. In the processing code it does the work and then tells the timer to fire again in 10 seconds, once only. Because the timer is now not firing periodically but is being re-started by its callback method then the callback is guaranteed to be single-threaded with no queue.
If you want to keep a constant interval, then it's a bit trickier as you have to decide what to do if the processing starts taking longer than the timer interval. One option is to do what you're currently doing but that will essentially end up with a lot of queued threads and eventual thread pool starvation. Another option is to simply discard the callback if there is already one in progress, e.g.
static Timer timer;
static object locker = new object();
public void Start()
{
var callback = new TimerCallback(DoSomething);
timer = new Timer(callback, null, 0, 10000);
}
public void DoSomething()
{
if (Monitor.TryEnter(locker))
{
try
{
// my processing code
}
finally
{
Monitor.Exit(locker);
}
}
}
The worst that can happen if the processing code takes more than 10s to execute is that you will be wasting 1 threadpool thread every time there's a new callback called (they will be waiting for in the lock statement). And if you take all the threadpool threads HttpWebRequest, ASP.NET, asynchronous delegate invocations... will suffer.
What I would do is to schedule the first callback immediately. Then, if you really need your DoSomething() to be called every 10s:
public void DoSomething ()
{
DateTime start = DateTime.UtcNow;
...
TimeSpan elapsed = (DateTime.UtcNow - start);
int due_in = (int) (10000 - elapsed.TotalMilliseconds);
if (due_in < 0)
due_in = 0;
timer.Change (due_in, Timeout.Infinite);
}
Or something along that line.
Let's say I have an existing System.Threading.Timer instance and I'd like to call Change on it to push it's firing time back:
var timer = new Timer(DelayCallback, null, 10000, Timeout.Infinite);
// ... (sometime later but before DelayCallback has executed)
timer.Change(20000, Timeout.Infinite);
I'm using this timer to perform an "idle callback" after a period of no activity. ("Idle" and "no activity" are application-defined conditions in this case...the specifics aren't terribly important.) Every time I perform an "action", I want to reset the timer so that it is always set to fire 10 seconds after that.
However, there is an inherent race condition because when I call Change, I can't tell if the Timer has already fired based on its old settings. (I can, of course, tell if my callback has happened but I can't tell if the CLR's internal timer thread has queued my callback to the threadpool and its execution is imminent.)
Now I know I can call Dispose on the timer instance and re-create it each time I need to "push it back". but this seems less efficient than just changing the existing timer. Of course it may not be...I'll run some micro-benchmarks in a bit and let you all know.
Alternatively, I can always keep track of the expected firing time (via DateTime.Now.AddSeconds(10)) and, if the original Timer fires, ignore it by checking DateTime.Now in the callback. (I have a nagging concern that this may not be 100% reliable on account of the Timer using TimeSpan and my check using DateTime...this may not be an issue but I'm not completely comfortable with it for some reason...)
My questions are:
Is there a good way for me to call Timer.Change and be able to know whether I managed to change it before the callback was queued to the threadpool? (I don't think so, but it doesn't hurt to ask...)
Has anyone else implemented (what I term) a "pushback timer" like this? If so, I'd love to hear how you tackled the problem.
This question is somewhat hypothetical in nature since I already have a couple of working solutions (based on Dispose and based on DateTime.Now)...I'm mainly interested in hearing performance-related suggestions (as I'll be "pushing back" the Timer VERY frequently).
Thanks!
it sounds like what you really want is the application-idle event
System.Windows.Forms.Application.Idle
Im interpreting your questions as a request for an implementatation of the IdleNotifier interface specified below. Also you state that ActionOccured() needs to be fast.
public delegate void IdleCallback();
public interface IdleNotifier
{
// Called by threadpool when more than IdleTimeSpanBeforeCallback
// has passed since last call on ActionOccured.
IdleCallback Callback { set; }
TimeSpan IdleTimeSpanBeforeCallback { set; }
void ActionOccured();
}
I provide an implementation with System.Threading.Timer below.
Important points about the implementation:
We accept that the timer can wake up at any time and make sure this is ok.
Since we assume the timer wakes relatively seldom we can do expensive work at these times.
Since we can do all logic in the timer callback all we need to do to "push the timer" is to remeber when last we pushed it.
Implementation:
public class IdleNotifierTimerImplementation : IdleNotifier
{
private readonly object SyncRoot = new object();
private readonly Timer m_Timer;
private IdleCallback m_IdleCallback = null;
private TimeSpan m_IdleTimeSpanBeforeEvent = TimeSpan.Zero;
// Null means there has been no action since last idle notification.
private DateTime? m_LastActionTime = null;
public IdleNotifierTimerImplementation()
{
m_Timer = new Timer(OnTimer);
}
private void OnTimer(object unusedState)
{
lock (SyncRoot)
{
if (m_LastActionTime == null)
{
m_Timer.Change(m_IdleTimeSpanBeforeEvent, TimeSpan.Zero);
return;
}
TimeSpan timeSinceLastUpdate = DateTime.UtcNow - m_LastActionTime.Value;
if (timeSinceLastUpdate > TimeSpan.Zero)
{
// We are no idle yet.
m_Timer.Change(timeSinceLastUpdate, TimeSpan.Zero);
return;
}
m_LastActionTime = null;
m_Timer.Change(m_IdleTimeSpanBeforeEvent, TimeSpan.Zero);
}
if (m_IdleCallback != null)
{
m_IdleCallback();
}
}
// IdleNotifier implementation below
public void ActionOccured()
{
lock (SyncRoot)
{
m_LastActionTime = DateTime.UtcNow;
}
}
public IdleCallback Callback
{
set
{
lock (SyncRoot)
{
m_IdleCallback = value;
}
}
}
public TimeSpan IdleTimeSpanBeforeCallback
{
set
{
lock (SyncRoot)
{
m_IdleTimeSpanBeforeEvent = value;
// Run OnTimer immediately
m_Timer.Change(TimeSpan.Zero, TimeSpan.Zero);
}
}
}
}
There are many straight-forward performance improvements on this code.
If anyone would be intrested in my first thoughts on this just ask me.
I've actually had to build my own "Timing" class for an MMORPG I've made. It could keep track of over 100,000 "entities" that had timers for processing AI, and other tasks. Based on different actions that could be taken, I would have to momentarily delay an event.
Now, my timing class was completely hand written, so it won't be exactly what you're looking for. But something that you could do that would be similar to the solution I came up with is to do a sort of:
while (sleepyTime > 0)
{
int temp = sleepyTime;
sleepyTime = 0;
Thread.Sleep(temp);
}
// here's where your actual code is.
Then, you can make a "Delay" method that basically just ads to sleepyTime.