Can I dispose a Threading.Timer in its callback?
I'm using Threading.Timer
, like:
new Timer(new TimerCallback(y=>
{
try
{
Save(Read(DateTime.Now));
// here i want to dispose this timer
}
catch
{
}
}),null,100000,10000);
How can I dispose this timer inside of a callback. or workaround? Update: Let me explain the situation. I want to try to call the method "Save", while it throws an exception. If it works, I need to stop the 开发者_开发百科timer.
Try this:
Timer timer = null;
timer = new Timer(new TimerCallback(y =>
{
try
{
Save(Read(DateTime.Now));
// here i want to dispose this timer
timer.Dispose();
}
catch
{
}
}));
timer.Change(10000, 10000);
EDIT:
I changed the above code slightly according to Chuu's suggestion. Note that if the TimerCallback is called simultanuously by different timer events, Timer.Dispose
may end up being called several times. Luckily the Timer
does not care if it is being disposed of several times.
Here's a better way to do this. When you use the constructor with only one param (TimerCallback), the state passed to the callback will be the timer itself.
Timer timer = new Timer(o =>
{
((Timer)o).Dispose();
//Your code here
});
//Start the timer
timer.Change(100000,10000);
Here is an example from the msdn docs :
public void StartTimer(int dueTime)
{
Timer t = new Timer(new TimerCallback(TimerProc));
t.Change(dueTime, 0);
}
private void TimerProc(object state)
{
// The state object is the Timer object.
Timer t = (Timer) state;
t.Dispose();
Console.WriteLine("The timer callback executes.");
}
http://msdn.microsoft.com/en-us/library/ms149618(v=vs.110).aspx
You need to keep the reference of the timer in a variable -
public class MyClass
{
private Timer _timer;
public void StartTimer()
{
_timer = new Timer(new TimerCallback(y=>{
try
{
Save(Read(DateTime.Now));
_timer.Dispose();
}
catch {
}
}),null,100000,10000);
}
}
Note: This is untested code. Please check if it works and update.
You'll have to store a reference to the timer somewhere and pass that in as state to the timer object itself. Try creating a class something like this:
public class TimerContainer
{
public Timer Timer { get; set; }
}
Then use it in your method like so:
Action<object> tcb = state =>
{
var container = (TimerConatiner)state;
try
{
Save(Read(DateTime.Now));
container.Timer.Dispose();
}
catch
{
// whatever...
}
};
var container = new TimerContainer();
container.Timer = new Timer(tcb, container, 100000, 10000);
Take care if you use multithreading or multitasking! if so, here you're the code and a solucion for a CancelAfter method extensor (.net 4.0):
private static object syncObj = new object();
public static void CancelAfter(this CancellationTokenSource source, int timeoutMilliseconds, Action code = null)
{
if (timeoutMilliseconds == 0) return; // No timeout
if (source == null)
{
throw new NullReferenceException();
}
if (timeoutMilliseconds < -1)
{
throw new ArgumentOutOfRangeException("timeout");
}
Timer timer = new Timer(delegate(object self)
{
lock (syncObj)
{
try
{
if (null != code)
code.Invoke();
source.Cancel();
((IDisposable)self).Dispose();
}
catch (ObjectDisposedException)
{
}
}
});
timer.Change(timeoutMilliseconds, -1);
}
}
Regards, Juanlu, ElGuerre
精彩评论