diff --git a/Rx.NET/Source/src/System.Reactive/Concurrency/ConcurrencyAbstractionLayerImpl.cs b/Rx.NET/Source/src/System.Reactive/Concurrency/ConcurrencyAbstractionLayerImpl.cs index 8af1f261e..9a92e55b3 100644 --- a/Rx.NET/Source/src/System.Reactive/Concurrency/ConcurrencyAbstractionLayerImpl.cs +++ b/Rx.NET/Source/src/System.Reactive/Concurrency/ConcurrencyAbstractionLayerImpl.cs @@ -132,11 +132,13 @@ public void StartThread(Action action, object state) private sealed class Timer : IDisposable { + private object _state; private Action _action; private volatile System.Threading.Timer _timer; public Timer(Action action, object state, TimeSpan dueTime) { + _state = state; _action = action; // Don't want the spin wait in Tick to get stuck if this thread gets aborted. @@ -144,23 +146,25 @@ public Timer(Action action, object state, TimeSpan dueTime) finally { // - // Rooting of the timer happens through the this.Tick delegate's target object, + // Rooting of the timer happens through the Timer's state // which is the current instance and has a field to store the Timer instance. // - _timer = new System.Threading.Timer(Tick, state, dueTime, TimeSpan.FromMilliseconds(System.Threading.Timeout.Infinite)); + _timer = new System.Threading.Timer(_ => Tick(_), this, dueTime, TimeSpan.FromMilliseconds(System.Threading.Timeout.Infinite)); } } - private void Tick(object state) + private static void Tick(object state) { + var timer = (Timer) state; + try { - _action(state); + timer._action(timer._state); } finally { - SpinWait.SpinUntil(IsTimerAssigned); - Dispose(); + SpinWait.SpinUntil(timer.IsTimerAssigned); + timer.Dispose(); } } @@ -173,6 +177,7 @@ public void Dispose() { _action = Stubs.Ignore; _timer = TimerStubs.Never; + _state = null; timer.Dispose(); }