Friday 14 May 2010

Properly disposing a System.Threading.Timer

The following test fixture shows how a timer can be properly disposed in order to ensure that the thread executing the callback has completed (or we've timed out waiting for it):

[TestClass]
public class TimerFixture
{
[TestMethod]
public void Check_timer_dispose_behaviour()
{
System.Threading.Timer timer = new System.Threading.Timer(new System.Threading.TimerCallback(OnTick), null, 100, 0);

while (!isProcessing) Thread.Sleep(50);

WaitHandle waitHandle = new AutoResetEvent(false);

timer.Dispose(waitHandle);

isStopping = true;

WaitHandle.WaitAll(new[] { waitHandle }, 1000);

Assert.IsFalse(isProcessing);
}

private void OnTick(object state)
{
isProcessing = true;

while (!isStopping) Thread.Sleep(100);

Thread.Sleep(200);

isProcessing = false;
}

private bool isStopping = false;
private bool isProcessing = false;
}

1 comment:

Unknown said...

Your test does neither check whether `Dispose` returns false (it can) nor whether `WaitAll` returns false (it will, on timeout).
So your tests are bound to fail (sporadically).

Problem is, once you add these fault detections, you'll see that under some circumstances `WaitAll` will timeout. To my knowledge, it's just not possible to properly synchronize using `Timer.Dispose(WaitHandle)` - it's broken.