Reliably Stop System.Threading.Timer

Reliably stop System.Threading.Timer?

like Conrad Frix suggested you should use the System.Timers.Timer class instead, like:

private System.Timers.Timer _timer = new System.Timers.Timer();
private volatile bool _requestStop = false;

public constructor()
{
_timer.Interval = 100;
_timer.Elapsed += OnTimerElapsed;
_timer.AutoReset = false;
_timer.Start();
}

private void OnTimerElapsed(object sender, System.Timers.ElapsedEventArgs e)
{
// do work....
if (!_requestStop)
{
_timer.Start();//restart the timer
}
}

private void Stop()
{
_requestStop = true;
_timer.Stop();
}

private void Start()
{
_requestStop = false;
_timer.Start();
}

Best way to disable a System.Threading.Timer

Setting a timer's initial value and interval to -1 (i.e. Change(-1, -1)) is not a "CPU heater." Timers don't use CPU resources. The callback method does, of course, but only during the (usually brief) time when it's executing.

In any case, it is not at all expensive to create a new timer, nor will disabling it with Change(-1, -1) have any negative performance consequences. Use whichever technique best fits your model.

How to STOP a System.Threading.Timer


I need to know how I can stop a System.Threading.Timer because when they order a taxi, cancel it after lets say 8 seconds then straight after they order another taxi, that taxi takes 2 seconds to come not 10 so it still uses the old taxi timer, how do I stop it?

Take a step back. You don't have to worry about canceling a timer if you never make one.

You are describing an asynchronous workflow with cancellation. C# and the .NET framework already has this feature, so use it rather than trying to roll your own.

Make an async workflow method that awaits a Task.Delay task that takes a CancellationToken. The continuation of the delay is the arrival of the taxi; the cancellation method causes the task to fail by canceling the token.

There is plenty of documentation on this mechanism, so start reading it. A good place to start is here:

https://msdn.microsoft.com/en-us/library/dd997364

How to stop a System.Threading.Timer and cancel any callback that is running?

According to the documentation, you should use the Dispose(WaitHandle) overload:

Releases all resources used by the current instance of Timer and signals when the timer has been disposed of.

When this method completes, it signals the WaitHandle specified by the notifyObject parameter.Use this overload of the Dispose method if you want to be able to block until you are certain that the timer has been disposed. The timer is not disposed until all currently queued callbacks have completed.

void Dispose()
{
timer.Change(Timeout.Infinite, Timeout.Infinite); //Stop timer

var waiter = new ManualResetEvent(false);
timer.Dispose(waiter);
waiter.WaitOne();
waiter.Dispose();

timerSync.Dispose();
//Dispose other things...
}

If you don't want to wait for the current callback to be executed at all, you could follow the IDisposable pattern:

Timer timer = new Timer(Timer_Tick, null, Timeout.Infinite, Timeout.Infinite);
Mutex timerSync = new Mutex();
private bool _disposed;

void Dispose()
{
_disposed = true;
...
}

void Timer_Tick()
{
if (_disposed)
{
return;
}

...
}

Is it possible to stop a threading.Timer immediately?

This is a "feature" of the Timer. The callback may run on a different thread and it does not even need to terminate before it is called again (for example if its execution takes more that 1000 ms). If you don't need this feature and it is OK to run the callback 1000 ms after the termination of the previous callback you can just avoid passing the period parameter and restart the timer manually at the end of the callback.

How do I gracefully stop a System.Threading.Timer?

With this code

 timer = new Timer( state => {
// simulate some work that takes ten seconds
Thread.Sleep( tickInterval * 10 );

// when the work is done, schedule the next callback in one second
timer.Change( tickInterval, Timeout.Infinite );
},
null,
tickInterval, // first callback in one second
Timeout.Infinite );

it is almost certain that you will Dispose the timer while it is sleeping.

You will have to safeguard the code after Sleep() to detect a Disposed timer. Since there is no IsDisposed property a quick and dirty static bool stopping = false; might do the trick.

Can I stop a System.Threading.Timer

There is no way to know the Thread on which a Threading.Timer callback will run ahead of time. Hence there is no general way to abort it. It is possible to have the callback itself communicate the Thread instance but it opens up a couple of race conditions

Note: In general using Abort is a bad practice. It's a fairly reliable way to end up with hard to detect deadlocks and / or resource leaks. It's much better to use a passive mechanism like CancellationToken

How to stop a System.Threading.Timer, then change its parameters and run it again?

I wouldn't re-invent the wheel. Microsoft already has a library that does this nicely for you. You should use Microsoft's Reactive Framework (aka Rx) - NuGet System.Reactive and add using System.Reactive.Linq;.

You can do this kind of thing:

IDisposable subscription =
Observable
.Interval(TimeSpan.FromSeconds(1.0))
.Subscribe(x => Console.WriteLine(x));

This will fire an event every second. If you want to stop it just call subscription.Dispose();

If you want a different period then pass in something like TimeSpan.FromDays(2.0).

Now, if you want to be able to change the period you can do this:

Subject<TimeSpan> subject = new Subject<TimeSpan>();

IObservable<long> interval =
subject
.Select(timespan => Observable.Interval(timespan))
.Switch();

IDisposable subscription =
interval
.Subscribe(x => Console.WriteLine(x));

Now, to start the interval going I would call this:

subject.OnNext(TimeSpan.FromSeconds(1.0));

If I now want to change it I just do this:

subject.OnNext(TimeSpan.FromHours(2.0));

And, again, to stop it just call subscription.Dispose();.



Related Topics



Leave a reply



Submit