什么是处置带有计时器的类的正确方法?(What is the proper way to Dispo

2019-10-23 02:32发布

比方说,我有其中有一个定时器对象,没有做任何重要的工作一类 - 只是一些GUI工作。 比方说,有2个场景中的定时器结束,每5分钟:

  1. Timer_Elapsed委托是有很多工作做,它需要2分钟才能完成。
  2. Timer_Elapsed委托有做一点工作,它需要几毫秒即可完成

什么是处置对象和定时器的正确方法? 确实的时间量Timer_Elapsed事件委托运行影响你对如何正确处置的决定呢?

Answer 1:

如果您需要处置期间停止你的定时器和工作仍可能在你的计时器委托,依赖于共享资源,被设置在进步的同时,你需要协调“关机”的过程。 下面的片段展示了这样的例子:

public class PeriodicTimerTask : IDisposable
{
    private readonly System.Timers.Timer _timer;
    private CancellationTokenSource _tokenSource;
    private readonly ManualResetEventSlim _callbackComplete;
    private readonly Action<CancellationToken> _userTask;

    public PeriodicTimerTask(TimeSpan interval, Action<CancellationToken> userTask)
    {
        _tokenSource = new CancellationTokenSource();
        _userTask = userTask;
        _callbackComplete = new ManualResetEventSlim(true);
        _timer = new System.Timers.Timer(interval.TotalMilliseconds);
    }

    public void Start()
    {
        if (_tokenSource != null)
        {
            _timer.Elapsed += (sender, e) => Tick();
            _timer.AutoReset = true;
            _timer.Start();
        }
    }

    public void Stop()
    {
        var tokenSource = Interlocked.Exchange(ref _tokenSource, null);
        if (tokenSource != null)
        {
            _timer.Stop();
            tokenSource.Cancel();
            _callbackComplete.Wait();
            _timer.Dispose();
            _callbackComplete.Dispose();
            tokenSource.Dispose();
        }
    }

    public void Dispose()
    {
        Stop();
        GC.SuppressFinalize(this);
    }

    private void Tick()
    {
        var tokenSource = _tokenSource;
        if (tokenSource != null && !tokenSource.IsCancellationRequested)
        {
            try
            {
                _callbackComplete.Wait(tokenSource.Token); // prevent multiple ticks.
                _callbackComplete.Reset();
                try
                {
                    tokenSource = _tokenSource;
                    if (tokenSource != null && !tokenSource.IsCancellationRequested)
                        _userTask(tokenSource.Token);
                }
                finally
                {
                    _callbackComplete.Set();
                }
            }
            catch (OperationCanceledException) { }
        }
    }
}

用法示例:

public static void Main(params string[] args)
{
    var periodic = new PeriodicTimerTask(TimeSpan.FromSeconds(1), cancel => {
        int n = 0;
        Console.Write("Tick ...");
        while (!cancel.IsCancellationRequested && n < 100000)
        {
            n++;
        }
        Console.WriteLine(" completed.");
    });
    periodic.Start();
    Console.WriteLine("Press <ENTER> to stop");
    Console.ReadLine();
    Console.WriteLine("Stopping");
    periodic.Dispose();
    Console.WriteLine("Stopped");
}

随着像下面的输出:

Press <ENTER> to stop
Tick ... completed.
Tick ... completed.
Tick ... completed.
Tick ... completed.
Tick ... completed.

Stopping
Stopped


Answer 2:

有多种方法可供选择,像亚历克斯在评论中说,这取决于是否委托将使用也配置对象。

比方说,我们有一个“最坏的情况”,其中委托确实需要使用这将是配置的对象。
来处理一个很好的办法是类似于方法Process对象具有: WaitForExit() 这种方法只会循环,直到它看到的委托完成的工作(有working这是之前设置和委托运行后布尔?)然后返回。 现在,你可以在使用这个类的代码是这样的:

// Time to shut down
myDisposable.WaitForFinish();
myDisposable.Dispose();

因此,我们基本上保证了委托处置它,停止任何形式的做过ObjectDisposedException



文章来源: What is the proper way to Dispose of a class with a Timer?