I'm using a Timer class that wraps CreateTimerQueueTimer and DeleteTimerQueueTimer.
Here is the class:
using System;
using System.Threading;
using MyCompany.Internal;
using TimerCallback = MyCompany.Internal.TimerCallback;
public class Timer : IDisposable
{
public Timer()
{
this.callback = this.ticked;
this.autoReset = true;
Computer.ChangeTimerResolutionTo(1);
this.priority = ThreadPriority.Normal;
}
public virtual event EventHandler Elapsed;
public virtual bool AutoReset
{
get
{
return this.autoReset;
}
set
{
this.autoReset = value;
}
}
public virtual ThreadPriority Priority
{
get
{
return this.priority;
}
set
{
this.priority = value;
}
}
public virtual void Start(int interval)
{
if (interval < 1)
{
throw new ArgumentOutOfRangeException("interval", "Interval must be at least 1 millisecond.");
}
if (Interlocked.CompareExchange(ref this.started, 1, 0) == 1)
{
return;
}
NativeMethods.CreateTimerQueueTimer(
out this.handle,
IntPtr.Zero,
this.callback,
IntPtr.Zero,
(uint)interval,
(uint)interval,
CallbackOptions.ExecuteInTimerThread);
}
public virtual void Stop()
{
if (Interlocked.CompareExchange(ref this.started, 0, 1) == 0)
{
return;
}
NativeMethods.DeleteTimerQueueTimer(IntPtr.Zero, this.handle, IntPtr.Zero);
}
public virtual void Dispose()
{
this.Stop();
}
private void ticked(IntPtr parameterPointer, bool unused)
{
if (!this.AutoReset)
{
this.Stop();
}
Thread.CurrentThread.Priority = this.Priority;
var elapsed = this.Elapsed;
if (elapsed != null)
{
elapsed(this, EventArgs.Empty);
}
}
private int started;
private IntPtr handle;
private volatile bool autoReset;
private ThreadPriority priority;
private readonly TimerCallback callback;
}
The problem is, after awhile I'm getting an SEHException when calling Start and Stop simultaneously from multiple threads. The Interlocked.CompareExchange methods should prevent DeleteTimerQueueTimer from being called once after Stop() is called, right? Even if Stop() is called simultaneously from different threads?
The SEHException is being thrown at DeleteTimerQueueTimer(); I assume it's because it's trying to delete a timer that has already been deleted, making the handle invalid. Doesn't the CompareExchange prevent DeleteTimerQueueTimer from being called more than once, even by multiple threads simultaneously?
The function Interlocked.CompareExchange prevent the variable 'started' from modified at same time from 2 threads, but the handle of the timer is the real one you want to protected, but the code fails to do in some cases.
For example, thread A call the start function, it execute the function Interlocked.CompareExchange and then this.started is 1; at this time thread A call the stop function, it sees that 'started' is one, so it will call function DeleteTimerQueueTimer to delete the timer, while the timer might not be created yet and the handle is invalid.
So you should protect the handle of the timer
Related
I am porting a windows C# application that polls at 50ms (for serial comms) to Linux (using Mono). We are currently using the ZylTimer (by ZylSoft) to generate "tick" events at each interval , however as this library wraps pInvoke calls to the windows multimedia library, we of course cannot use this.
//i.e.
timZylComms.Tick += new ZylTimer.TickEventHandler(timZylComms_Tick);
timTimeout.Tick += new ZylTimer.TickEventHandler(timTimeout_Tick);
So, this leads me to ask if either there exists an alternative I can use under Mono?
Would the best approach be to extend the "Stopwatch" class (which counts at a high resolution) with a Tick event?
Or are there any linux libraries I can wrap to reproduce this functionality?
Or is there some other way of achieving this?
Appreciate any thoughts on this.
EDIT:
Would there be any problems with going with this:
internal class LinuxHiResTimer{
internal event EventHandler Tick;
private System.Diagnostics.Stopwatch watch;
internal int Interval{ get; set;}
private bool enabled;
internal bool Enabled {
get{ return enabled; }
set {
if (value) {
watch.Start ();
Task.Run (tickGenerator);
enabled = value;
} else {
enabled = value;
}
}
}
private async Task tickGenerator(){
while (enabled){
if (watch.ElapsedMilliseconds > Interval) {
watch.Reset ();
if (Tick != null)
Tick (this, new EventArgs ());
} else {
float fWaitPeriod = (float)(0.8 * (Interval - watch.ElapsedMilliseconds));
if (fWaitPeriod>20)
await Task.Delay(TimeSpan.FromMilliseconds(fWaitPeriod));
}
}
watch.Stop ();
}
internal LinuxHiResTimer(){
watch = new Stopwatch ();
}
~LinuxHiResTimer(){
watch.Stop ();
}
}
This is what I have now.
It does the job (tested with generating ticks at 25ms).
It works by using nanosleep() (through the Mono.Unix.Native wrapper), and I would like to share this with others in case they are looking to implement something similar.
using Mono.Unix.Native;
namespace drone.StackOverflow{
internal class LinuxHiResTimer {
internal event EventHandler Tick; // Tick event
private System.Diagnostics.Stopwatch watch; // High resolution time
const uint safeDelay = 0; // millisecond (for slightly early wakeup)
private Timespec pendingNanosleepParams = new Timespec();
private Timespec threadNanosleepParams = new Timespec();
object lockObject = new object();
internal long Interval {
get{
double totalNanoseconds;
lock (lockObject) {
totalNanoseconds= (1e9 * pendingNanosleepParams.tv_sec)
+ pendingNanosleepParams.tv_nsec;
}
return (int)(totalNanoseconds * 1e-6);//return value in ms
}
set{
lock (lockObject) {
pendingNanosleepParams.tv_sec = value / 1000;
pendingNanosleepParams.tv_nsec = (long)((value % 1000) * 1e6);//set value in ns
}
}
}
private bool enabled;
internal bool Enabled {
get { return enabled; }
set {
if (value) {
watch.Start();
enabled = value;
Task.Run(()=>tickGenerator()); // fire up new thread
}
else {
lock (lockObject) {
enabled = value;
}
}
}
}
private Task tickGenerator() {
bool bNotPendingStop;
lock (lockObject) {
bNotPendingStop = enabled;
}
while (bNotPendingStop) {
// Check if thread has been told to halt
lock (lockObject) {
bNotPendingStop = enabled;
}
long curTime = watch.ElapsedMilliseconds;
if (curTime >= Interval) {
watch.Restart ();
if (Tick != null)
Tick (this, new EventArgs ());
} else {
long iTimeLeft = (Interval - curTime); // How long to delay for
if (iTimeLeft >= safeDelay) { // Task.Delay has resolution 15ms//await Task.Delay(TimeSpan.FromMilliseconds(iTimeLeft - safeDelay));
threadNanosleepParams.tv_nsec = (int)((iTimeLeft - safeDelay) * 1e6);
threadNanosleepParams.tv_sec = 0;
Syscall.nanosleep (ref threadNanosleepParams, ref threadNanosleepParams);
}
}
}
watch.Stop();
return null;
}
}
Usage:
private myMainFunction(){
LinuxHiResTimer timReallyFast = new LinuxHiResTimer();
timReallyFast.Interval=25; //
timReallyFast.Tick += new EventHandler(timReallyFast_Tick);
timReallyFast.Enabled = true;
}
private void timReallyFast_Tick(System.Object sender, System.EventArgs e) {
// Do this quickly i.e.
PollSerialPort();
}
Let's say I have a class which has a Timer object that doesn't do any critical work - just some GUI work. Let's say there are 2 scenarios where the timer elapses every 5 minutes:
in the Timer_Elapsed delegate there is a lot of work that is done and it takes 2 minutes to complete.
in the Timer_Elapsed delegate there is little work to be done and it takes a couple of milliseconds to complete
What is the proper way to dispose of the object & timer? Does the amount of time the Timer_Elapsed event delegate runs influence your decision on how to Dispose properly?
If, you need to stop your timer during disposal, and work could still be in progress in your timer delegate, that relies on shared resources, being disposed at the same time, you need to coordinate the "shutdown" process. The below snippet shows an example of doing this:
public class PeriodicTimerTask : IDisposable
{
private readonly System.Timers.Timer _timer;
private CancellationTokenSource _tokenSource;
private readonly ManualResetEventSlim _callbackComplete;
private readonly Action<CancellationToken> _userTask;
public PeriodicTimerTask(TimeSpan interval, Action<CancellationToken> userTask)
{
_tokenSource = new CancellationTokenSource();
_userTask = userTask;
_callbackComplete = new ManualResetEventSlim(true);
_timer = new System.Timers.Timer(interval.TotalMilliseconds);
}
public void Start()
{
if (_tokenSource != null)
{
_timer.Elapsed += (sender, e) => Tick();
_timer.AutoReset = true;
_timer.Start();
}
}
public void Stop()
{
var tokenSource = Interlocked.Exchange(ref _tokenSource, null);
if (tokenSource != null)
{
_timer.Stop();
tokenSource.Cancel();
_callbackComplete.Wait();
_timer.Dispose();
_callbackComplete.Dispose();
tokenSource.Dispose();
}
}
public void Dispose()
{
Stop();
GC.SuppressFinalize(this);
}
private void Tick()
{
var tokenSource = _tokenSource;
if (tokenSource != null && !tokenSource.IsCancellationRequested)
{
try
{
_callbackComplete.Wait(tokenSource.Token); // prevent multiple ticks.
_callbackComplete.Reset();
try
{
tokenSource = _tokenSource;
if (tokenSource != null && !tokenSource.IsCancellationRequested)
_userTask(tokenSource.Token);
}
finally
{
_callbackComplete.Set();
}
}
catch (OperationCanceledException) { }
}
}
}
Usage example:
public static void Main(params string[] args)
{
var periodic = new PeriodicTimerTask(TimeSpan.FromSeconds(1), cancel => {
int n = 0;
Console.Write("Tick ...");
while (!cancel.IsCancellationRequested && n < 100000)
{
n++;
}
Console.WriteLine(" completed.");
});
periodic.Start();
Console.WriteLine("Press <ENTER> to stop");
Console.ReadLine();
Console.WriteLine("Stopping");
periodic.Dispose();
Console.WriteLine("Stopped");
}
With output like below:
Press <ENTER> to stop
Tick ... completed.
Tick ... completed.
Tick ... completed.
Tick ... completed.
Tick ... completed.
Stopping
Stopped
There are multiple approaches to this, and like Alex said in the comments it depends on whether or not objects the delegate will be using are also disposed.
Let's say we have a "worst-case" scenario, in which the delegate does need to use objects which would be disposed.
A good way to handle this would be similar to a method the Process object has: WaitForExit(). This method would simply loop until it sees the delegate is done working (have a working bool which is set before and after the delegate runs?) then returns. Now you can have something like this in the code using that class:
// Time to shut down
myDisposable.WaitForFinish();
myDisposable.Dispose();
Thus we are essentially ensuring the delegate is done before disposing of it, stopping any sort of ObjectDisposedException.
I have an Elapsed method in which I have a while loop. If the timer is disabled/stopped from another thread, I would like this loop to stop. Can I rely on the timer's Enabled property in the Elapsed method for this or should I create a "volatile bool timerEnabled" variable just to be sure. My testings show that it's OK, but I'd like to be sure of this before putting it in production.
This is what I'm trying to achieve (not actual code but close)
private volatile bool isElapsedAlreadyRunning
void myTimer_Elapsed(object sender, ElapsedEventArgs e)
{
if (!isElapsedAlreadyRunning) // to prevent reentrance
{
isElapsedAlreadyRunning = true;
try
{
while (myTimer.Enabled && some other condition)
{
do stuff
}
}
finally
{
isElapsedAlreadyRunning = false;
}
}
}
myTimer.Start() and myTimer.Stop() are in other methods that can be called frrom other threads
I'm using the System.Timers.Timer class
If you have any other comment or see any pitfall in this design feel free to comment :)
Thanks
Edit :
Man, threading is hard. Based on the answers and other stackoverflow questions (this answer particularly) this would be the way to do it (I hope this time it's OK)
public class NoLockTimer : IDisposable
{
private readonly System.Timers.Timer _timer;
private bool _isTimerStopped = false;
private readonly object _isTimerStoppedLock = new object();
public NoLockTimer()
{
_timer = new System.Timers.Timer { AutoReset = false, Interval = 1000 };
_timer.Elapsed += delegate
{
try
{
while (!IsTimerStopped && some other condition)
{
// do stuff
}
}
catch (Exception e)
{
// Do some logging
}
finally
{
if (!IsTimerStopped)
{
_timer.Start(); // <- Manual restart.
}
}
};
_timer.Start();
}
public void Stop()
{
IsTimerStopped = true;
if (_timer != null)
{
_timer.Stop();
}
}
private bool IsTimerStopped
{
get
{
lock (_isTimerStoppedLock)
{
return _isTimerStopped;
}
}
set
{
lock (_isTimerStoppedLock)
{
_isTimerStopped = value;
}
}
}
public void Dispose()
{
Stop();
if (_timer != null)
{
_timer.Dispose();
}
}
}
No, this is not safe. The Elapsed event handler is called on a threadpool thread. You cannot predict when that thread actually calls your method, it depends on what other TP threads are running in the process. Having two calls in flight at the same time is technically possible. Which makes the volatile keyword on the isElapsedAlreadyRunning variable not nearly good enough to ensure that the method is thread-safe, you must use the lock keyword or Monitor.TryEnter() instead.
This problem disappears when you set the Timer's AutoReset property to false. Be sure to restart the timer in a finally block, another nasty problem with the Timer.Elapsed event is that exceptions get swallowed without diagnostic. System.Threading.Timer is an all-around better timer with fewer surprises like this.
The Timer.Enabled property has a similar problem, you'll always see it late.
Your guard with isElapsedAlreadyRunning is obviously not thread-safe.
But you can simply replace it with a lock(...) { ...} statement.
Consider this example:
When the user clicks a button, ClassA fires OnUserInteraction event rapidly 10 times. ClassB is attached to this event and in it's event handler it fires ClassC's Render method. In the Render method the AxisAngleRotation3D is executed, but every single animation is lasting 1 second.
In this scenario all 10 AxisAngleRotation3D animations are executed almost at the same time, but I would want them to execute one after another. As I understand threads, I would probably have to implement a thread queue in ClassB, where the Completed event of the AxisAngleRotation3D signals that the next event is allowed to fire...?
Is this correct and how can I achieve this?
Have a task queue. Simply put, have a ConcurrentQueue<Func<bool>> field or similar, and add tasks to it as necessary. Then have your task execution thread pop Func<bool> delegates off the queue and invoke them. If they return true, they're done. If they return false, add them back onto the queue, as they couldn't complete at that time.
Here's an example:
using System;
using System.Collections.Concurrent;
using System.Threading;
namespace Example
{
public class TaskScheduler : IDisposable
{
public const int IDLE_DELAY = 100;
private ConcurrentQueue<Func<bool>> PendingTasks;
private Thread ExecuterThread;
private volatile bool _IsDisposed;
public bool IsDisposed
{
get { return _IsDisposed; }
}
public void EnqueueTask(Func<bool> task)
{
PendingTasks.Enqueue(task);
}
public void Start()
{
CheckDisposed();
if (ExecuterThread != null)
{
throw new InvalidOperationException("The task scheduler is alreader running.");
}
ExecuterThread = new Thread(Run);
ExecuterThread.IsBackground = true;
ExecuterThread.Start();
}
private void CheckDisposed()
{
if (_IsDisposed)
{
throw new ObjectDisposedException("TaskScheduler");
}
}
private void Run()
{
while (!_IsDisposed)
{
if (PendingTasks.IsEmpty)
{
Thread.Sleep(IDLE_DELAY);
continue;
}
Func<bool> task;
while (!PendingTasks.TryDequeue(out task))
{
Thread.Sleep(0);
}
if (!task.Invoke())
{
PendingTasks.Enqueue(task);
}
}
}
public void Dispose()
{
CheckDisposed();
_IsDisposed = true;
}
}
}
ClassB could add the event to a queue and then render them one at a time (possibly use a timer to read from the queue).
I have a System.Timers.Timer object that I want to use, but I don't want the processing tied to the Timer to interfere with normal to high priority threads. In other words, I'd like to say that I want to process X every 5 seconds as long as nothing else is running.
How could I ensure that my Timer operations are running in a low-priority manner?
The nice thing about System.Timers.Timer is that you can assign a synchronzing object via the SynchronizingObject property and then exploit it to run the Elapsed event a thread whose priority can be controlled.
Just assign an instance of the ElapsedEventReceiver to the SynchronizingObject property of your timer.
Disclaimer: I whipped this up pretty fast so you will need to add your own finishing touches to make it more robust.
public class ElapsedEventReceiver : ISynchronizeInvoke
{
private Thread m_Thread;
private BlockingCollection<Message> m_Queue = new BlockingCollection<Message>();
public ElapsedEventReceiver()
{
m_Thread = new Thread(Run);
m_Thread.Priority = ThreadPriority.BelowNormal;
m_Thread.IsBackground = true;
m_Thread.Start();
}
private void Run()
{
while (true)
{
Message message = m_Queue.Take();
message.Return = message.Method.DynamicInvoke(message.Args);
message.Finished.Set();
}
}
public IAsyncResult BeginInvoke(Delegate method, object[] args)
{
Message message = new Message();
message.Method = method;
message.Args = args;
m_Queue.Add(message);
return message;
}
public object EndInvoke(IAsyncResult result)
{
Message message = result as Message;
if (message != null)
{
message.Finished.WaitOne();
return message.Return;
}
throw new ArgumentException("result");
}
public object Invoke(Delegate method, object[] args)
{
Message message = new Message();
message.Method = method;
message.Args = args;
m_Queue.Add(message);
message.Finished.WaitOne();
return message.Return;
}
public bool InvokeRequired
{
get { return Thread.CurrentThread != m_Thread; }
}
private class Message : IAsyncResult
{
public Delegate Method;
public object[] Args;
public object Return;
public object State;
public ManualResetEvent Finished = new ManualResetEvent(false);
public object AsyncState
{
get { return State; }
}
public WaitHandle AsyncWaitHandle
{
get { return Finished; }
}
public bool CompletedSynchronously
{
get { return false; }
}
public bool IsCompleted
{
get { return Finished.WaitOne(0); }
}
}
}
Probably the easiest way would be to have a "busy" flag (or count), and ignore the timer ticks as long as it's non-zero.
P.S. Changing thread priorities is not recommended. It's hardly ever necessary.