保证System.Timers.Timer完成

问题描述 投票:0回答:1

我有一个计时器,我试图在 dispose 方法中关闭它,但我需要 100% 确定它已完成运行,并且我们不再有对 ElapsedEventHandler 的杂散回调。 我知道您无法检查回调是否已完成,因此我试图涵盖所有基础,以确保不会发生崩溃并且消息全部从我的队列中删除。

我已经实现了 StopTimer bool,因此在我处理时计时器不会自行重新启动。 我有一个 SemaphoreSlim 阻塞计时器已用方法。 我设置了等于计时器运行时间间隔 2 倍的延迟,以确保计时器应该完成其最后一个周期。

我也不确定这是否是正确的方法,或者我是否应该停止计时器并让 GC 负责清理工作?

public class MessageWriter : IDisposable
{
    public delegate void WriteMessageDelegate(OutputMessage messageQueue);
    private ConcurrentQueue<OutputMessage> MessageQueue = new ConcurrentQueue<OutputMessage>();
    public WriteMessageDelegate OutputToDevice;

    private System.Timers.Timer WriteTimer { get; set; }
    public int TimerInterval { get; set; }
    private SemaphoreSlim WritingMessages;
    private bool RunTimer { get; set; }

    private bool _disposed = false;

    public MessageWriter(double timerInterval)
    {
        TimerInterval = TimerInterval;

        RunTimer = true;

        WritingMessages = new SemaphoreSlim(1);

        WriteTimer = new System.Timers.Timer();
        WriteTimer.AutoReset = false;
        WriteTimer.Interval = TimerInterval;
        WriteTimer.Elapsed += WriteTimerElapsed;
    }

    private void WriteTimerElapsed(object sender, ElapsedEventArgs e)
    {
        try
        {
            WritingMessages.Wait();

            EmptyQueue();

            if (RunTimer)
                WriteTimer.Start();
        }
        catch (Exception)
        {
            //Nothing we can do here, this is the logger
            Console.WriteLine("Exception with Log timer - : " + ex.Message);
        }
        finally
        {
            WritingMessages.Release();
        }
    }

    private void EmptyQueue()
    {
        while (MessageQueue.TryDequeue(out var message))
        {
            OutputToDevice?.Invoke(message);
        }
    }

    protected virtual void Dispose(bool disposing)
    {
        if (_disposed)
            return;

        if (disposing)
        {
        }

        //Prevent timer running again
        RunTimer = false;

        //Disable timer if its running
        if (WriteTimer != null)
        {
            WriteTimer.Enabled = false;
            WriteTimer.Stop();
            WriteTimer.Dispose();
        }

        //Wait for double the timer interval
        System.Threading.Thread.Sleep(TimerInterval + TimerInterval);

        //Wait until this message writer has finished
        WritingMessages.Wait();

        //Release the semaphore so the timer can run again if it needs to
        WritingMessages.Release();

        //Get rid of any messages left in the queue
        EmptyQueue();

        //Dispose of the delegate
        OutputToDevice = null;

        // Free any unmanaged objects here.
        _disposed = true;
    }

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

    ~MessageWriter()
    {
        Dispose(false);
    }
}
c# dispose system.timers.timer
1个回答
0
投票

您可以在需要时处置计时器,无需任何额外操作。任何正在进行的 WriteTimerElapsed 都会继续,不再触发任何计时器。

WriteTimerElapsed 应该将消息队列处理至空。

这里没有隐藏风险。

© www.soinside.com 2019 - 2024. All rights reserved.