2012-04-04 2 views
3

Вот трассировки стека:Любые идеи о том, что может привести к тому, что свойство System.Timers.Timer.set_Enabled может вызвать исключение System.NullReferenceException?

2012-03-16 19: 15: 09Z Е System.NullReferenceException: Ссылка на объект не указывает на экземпляр объекта.
в System.Timers.Timer.set_Enabled (Логическое значение)
в System.Timers.Timer.Stop()

Вот код:

Таймер объявлен закрытой переменной-члена.

Private _myTimer As System.Timers.Timer 

Инициализировать метод таймера.

Private Sub InitializeMyTimer() 

    _myTimer = New System.Timers.Timer 

    _myTimer.Interval = My.Settings.TimeoutSeconds * 1000 
    _myTimer.Start() 

    AddHandler _myTimer.Elapsed, AddressOf MyTimer_Elapsed 

End Sub 

Timer прошедший способ. WsMethodAsync вызывает метод веб-службы .asmx.

Private Sub MyTimer_Elapsed(ByVal sender As Object, ByVal e As  System.Timers.ElapsedEventArgs) 

    Try 

     _myTimer.Stop() 

     Using thisWSHelper As New WSHelper 

      thisWsHelp.WsMethodAsync() 

     End Using 

     _myTimer.Start() 

    Catch ex As Exception 

     LogAndShowException(ex) 

    End Try 

End Sub 

Таймер должен иметь значение, иначе вызов Timer.Stop() будет выдавать исключение. Это спорадическая ошибка, и я просто пытаюсь понять, испытал ли кто-нибудь это раньше, или если у кого-то есть идеи о том, что может быть причиной этого. Это происходит в приложении WinForms в обработчике событий для прошедшего события таймера, но это происходит только периодически на компьютере пользователя. Я сам не смог воспроизвести ошибку.

+0

Сбой многопоточности, то есть, вероятно, вы получаете доступ к таймеру из нескольких потоков. – CodesInChaos

+0

Вы должны отредактировать вопрос и добавить код. (Я проголосовал за повторное открытие) –

+0

Почти все объекты .net могут быть записаны только из одного потока за раз. – CodesInChaos

ответ

2

Ну, давайте предположим, что вы поняли, что класс System.Timers.Timer реализует IDisposable, и что вы писали код, чтобы правильно расположить таймер, как следует:

Private Sub OnDisposed(ByVal sender As Object, ByVal e As EventArgs) Handles MyBase.Disposed 
    If myTimer IsNot Nothing Then 
     myTimer.Dispose() 
     myTimer = Nothing 
    End If 
End Sub 

Да, это будет идти Kaboom один раз в какое-то время. Событие Elapsed поднимается потоком пула потоков и может запускаться в любое нечетное время. Это может занять несколько секунд, если threadpool особенно занят. Устранение таймера не предотвращает запуск события, поток tp уже находится в полете. Таким образом, с этим конкретным кодом, весьма вероятно, что вы получите NRE. Просто иногда, когда вы отлаживаете код.

Прекращение работы с System.Timers.Timer довольно сложно, вы никогда не можете быть уверены, что событие Elapsed не будет срабатывать после того, как вы его отключили. Напишите оборонительно и имейте в виду, что это возможно. И пользу System.Threading.Timer.

1

Во-первых, причина, что вы видите эти случайные исключения:

System.Timers.Timer использует в качестве System.Threading.Timer, и, как сказал Ганс Passant, каждая итерация выполняется в другом потоке. Это позволяет сделать ваше событие Elapsed после отключения таймера, потому что новая итерация может быть запущена до того, как будет выполнен предыдущий.

Как работает System.Timers.Timer, он отключает базовый System.Threading.Timer и устанавливает его в положение «Нет». В редком (это слово избыточное?) Состояние гонки, ваш таймер попытается запустить Dispose на свой основной таймер, пока он установлен на «Нет», в результате чего будет NullReferenceException.


Одно решение было бы установить Timer.AutoReset свойство Ложные и перезапустить таймер в вашем Elapsed случае.

Смежные вопросы