Как правильно остановить однопоточную службу Windows (onStop)?
У меня есть служба Windows, написанная на VS 2010 / .NET 4.0.
Служба работает по схеме приведенного ниже фрагмента кода: используя таймер, она выполняет желаемое поведение каждые пару минут. Требование "желаемого поведения", которое выполняется каждые пару минут, теперь переросло в работу, которая занимает примерно 10 секунд.
Мне нужен только один поток в этом сервисе, нет причин создавать несколько потоков, поэтому я назвал службу Windows однопоточным.
Меня беспокоит то, что если кто-то останавливает службу через консоль управления, это может быть как раз в течение тех 10 секунд работы, которые иногда выполняет служба.
Я немного читал о SO и о том, как остановить службу, но немного растерялся. Иногда создаются WorkerThreads, иногда создаются ManualResetEvents, но до сих пор я не мог полностью понять лучший способ продвижения вперед для моей службы Windows.
Я думаю, что мне нужно проверить в течение 10 секунд выполнения какого-либо флага, а затем продолжить, только если этот флаг не говорит мне, что я должен остановиться. И в методе onStop мне, вероятно, нужно подождать, пока обработка не будет завершена должным образом.
Так много для теории;), но каков мой лучший путь вперед, также учитывая фрагмент кода ниже?
Спасибо всем!
Public Class MyService
Public _timer As System.Timers.Timer
Protected Overrides Sub OnStart(ByVal args() As String)
_timer = New System.Timers.Timer()
'more timer settings
AddHandler _timer.Elapsed, AddressOf _timer_Tick
_timer.Start()
End Sub
Protected Overrides Sub OnStop()
' ????????????????????????
End Sub
Private Sub _timer_Tick(ByVal sender As System.Object, ByVal e As System.EventArgs)
SyncLock Me
try
_timer.Stop()
catch ex as Exception
finally
_timer.Start()
end try
End SyncLock
End Sub
End Class
1 ответ
Просто возьмите блокировку, чтобы OnStop() не мог работать одновременно с обработчиком событий Elapsed:
Protected Overrides Sub OnStop()
SyncLock Me
_timer.Stop()
End SyncLock
End Sub
Который может участвовать в гонке, обработчик событий Elapsed, возможно, уже запланирован для запуска, но еще не вошел в блокировку. Поэтому убедитесь, что таймер все еще включен:
Private Sub _timer_Elapsed(ByVal sender As Object, ByVal e As EventArgs)
SyncLock Me
If Not _timer.Enabled Return
'' etc..
Пользуйся выделенным объектом блокировки вместо Меня. И следите за 30 секундами, которые сервисный контроллер готов подождать, прежде чем сдаться, вы приближаетесь.