Reputation: 171178
I'd like to use a System.Threading.Timer
to execute once. That timer is supposed to be deterministically cleaned up by calling Dispose
as soon as it is no longer needed (which is when the callback fires).
The problem is that the callback cannot reliably obtain a reference to the Timer
!
System.Threading.Timer timer = null;
timer = new System.Threading.Timer(_ =>
{
Console.WriteLine("Elapsed.");
//Dispose the timer here, but timer might be null!
timer.Dispose(); //BUG
}, null, TimeSpan.FromSeconds(1), TimeSpan.Zero);
The variable timer
might not be initialized when the callback fires. This code doesn't work in all cases because it contains a race condition.
How can we use System.Threading.Timer
to create a one-shot timer with deterministic cleanup?
(Better ways to create a one-shot timer/delay are out of scope for this question. I'm intentionally asking this in a specific way.)
Upvotes: 3
Views: 1872
Reputation: 39132
Change to the constructor of Timer that only receives a callback so that it will pass itself in the state parameter. Use Change()
to set it up immediately afterwards:
System.Threading.Timer timer = null;
timer = new System.Threading.Timer((state) =>
{
Console.WriteLine("Elapsed.");
// Dispose of the timer here:
((System.Threading.Timer)state).Dispose();
});
timer.Change(TimeSpan.FromSeconds(1), TimeSpan.Zero);
If you don't like to use the state
parameter you can also use closure variable like the code in the question does it. The key is not starting the timer with the constructor. Only start it after a reference to the timer has been stored.
Upvotes: 7