usr
usr

Reputation: 171178

How can a one-shot System.Threading.Timer dispose itself?

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

Answers (1)

Idle_Mind
Idle_Mind

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

Related Questions