У меня есть таймер, который я пытаюсь закрыть в методе удаления, но мне нужно быть на 100% уверенным, что он завершил работу и у нас больше нет случайных обратных вызовов к ElapsedEventHandler.
Я знаю, что вы не могу проверить, завершились ли обратные вызовы, поэтому я пытаюсь охватить все основы, чтобы гарантировать, что сбоев не произойдет и все сообщения будут удалены из моей очереди.
Я реализовал bool StopTimer, поэтому таймер не перезапустится, пока я утилизирую.
У меня есть метод SemaphoreSlim, блокирующий истекшие таймеры.
Я установил задержку, равную 2-кратному интервалу времени, истекшему таймерами, чтобы гарантировать таймер должен был завершить свой последний цикл.
Я также не уверен, правильный ли это подход, или мне следует просто остановить таймер и позволить GC позаботиться об очистке?< /p>
public class MessageWriter : IDisposable
{
public delegate void WriteMessageDelegate(OutputMessage messageQueue);
private ConcurrentQueue MessageQueue = new ConcurrentQueue();
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);
}
}
Подробнее здесь: https://stackoverflow.com/questions/788 ... s-finished