如何停止System.Threading.Timer并取消正在运行的任何回调?

时间:2018-07-30 01:58:13

标签: c# multithreading timer mutex

我的代码示例:

Timer timer = new Timer(Timer_Tick, null, Timeout.Infinite, Timeout.Infinite);
Mutex timerSync = new Mutex();

void StartWork()
{
    timer.Change(0, 1); //Start timer
    //Do something...
}

void Dispose()
{
    timer.Change(Timeout.Infinite, Timeout.Infinite); //Stop timer
    timer.Dispose();
    timerSync.Dispose();
    //Dispose other things...
}

void Timer_Tick()
{
    if (timerSync.WaitOne(0))
    {
        try
        {
            //Do something...
        }
        catch (Exception)
        {
            //If any exception occurs, abort the "Tick" callback!
            return;
        }
        finally
        {
            //Whatever happens, release the mutex!
            timerSync.ReleaseMutex();
        }
    }
}

当我停止计时器并处理它时,这不会停止当前的回调,这会产生错误。
特别是,如果正在运行回调,则会得到与互斥锁有关的ObjectDisposedException。
对于执行的结构方式,如果我在“ Dispose”方法上使用该互斥锁,则会导致死锁。
我已经想到了一种解决方案:使用另一个try-catch块来处理与互斥锁有关的异常。

但是我想知道是否有一种方法可以强制取消计时器的任何回调。

1 个答案:

答案 0 :(得分:2)

根据文档,您应该使用Dispose(WaitHandle)重载:

  

释放当前计时器实例使用的所有资源,并在计时器被处置后发出信号。

     

此方法完成后,它会发出由WaitHandle参数指定的notifyObject的信号。如果希望能够阻塞,请使用Dispose方法的重载,直到确定计时器已被处置。在所有当前排队的回调完成之前,不会释放计时器。

void Dispose()
{
    timer.Change(Timeout.Infinite, Timeout.Infinite); //Stop timer

    var waiter = new ManualResetEvent(false);
    timer.Dispose(waiter);
    waiter.WaitOne();
    waiter.Dispose();

    timerSync.Dispose();
    //Dispose other things...
}

如果您根本不想等待当前的回调执行,则可以遵循IDisposable模式:

Timer timer = new Timer(Timer_Tick, null, Timeout.Infinite, Timeout.Infinite);
Mutex timerSync = new Mutex();
private bool _disposed;

void Dispose()
{
     _disposed = true;
    ...
}

void Timer_Tick()
{
    if (_disposed)
    {
        return;
    }

    ...
}