Выбрасывание исключений в методе обратного вызова для таймеров
Я не смог найти ответ на этот вопрос где угодно...
Что происходит с исключениями, вызванными методом обратного вызова для System.Threading.Timer(или в обработчике событий для System.Timers.Timer). Является ли исключение распространенным в потоке, на котором был создан таймер или потерялся ли исключение?
Каковы побочные эффекты бросания исключения в функции обратного вызова таймера?
Каким будет правильный способ оповестить поток создания таймера о том, что было создано исключение в рабочем потоке (метод обратного вызова)?
Спасибо за ваше время.
Ответы
Ответ 1
Исключение не передается обратно вызывающему потоку. Если вы хотите, чтобы это было, вы можете добавить блок catch
и выяснить способ оповещения о вызывающем потоке. Если вызывающий поток представляет собой поток WinForms или WPF UI, вы можете использовать класс SynchronizationContext
для передачи вызова в поток пользовательского интерфейса. В противном случае вы можете использовать потокобезопасную очередь (или блокировку синхронизации) и периодически проверять ее в другом потоке.
System.Timers.Timer
тихо проглатывает исключения и продолжает таймер (хотя это может быть изменено в будущих версиях фреймворка); System.Threading.Timer
завершает работу программы.
Ответ 2
Я не знаю, какой вариант лучше, но когда я использую таймер обратного вызова, я обычно бросаю исключения и позволяю им пузыриться до основной процедуры обратного вызова, где я обрабатываю их изящно. Поток продолжает работать на таймере, как он должен.
Необработанные исключения в потоке (System.Threading.Timer) остановят всю вашу программу.
Ответ 3
Я не знаю, лучшее ли это решение, но то, что я сделал, было небольшим обходным решением. Мой вызывающий поток подписался на событие для исключения исключений из потоков. Поэтому, когда исключение происходит в некотором потоке, скажем, в событии TimerElapsed, затем формируйте блок catch, который я вызываю в качестве аргумента событию для объекта исключения события.
EventHolderCallingClass: он должен определить делегат и событие, как показано ниже.
public class EventHolderCallingClass
{
public delegate void HandleExceptionEventDelegate(Exception exception);
public event HandleExceptionEventDelegate HandleExceptionEvent ;
void Timer_Elapsed(object sender, System.Timers.ElapsedEventArgs e)
{
try
{
//some operation which caused exception.
}
catch(Exception exception)
{
if(HandleExceptionEvent!=null)
HandleExceptionEvent(exception)
}
}
}
Класс обработчика событий (обработчик исключений):
public EventHandlerClassConstructor()
{
EventHolderCallingClass.HandleExceptionEvent += new EventHolderCallingClass.HandleExceptionEventDelegate(HandleExceptionEventHandler);
}
void HandleExceptionEventHandler(Exception exception)
{
//handle exception here.
}