Question

I have got a windows service written in VS 2010 / .NET 4.0.

The service is following the scheme of the code snippet below: Using a timer, it executes some desired behaviour every couple of minutes. The requirement for the "desired behaviour" that's executed every couple of minutes has now grown into work that takes roughly 10 seconds.

I only need a single thread in that service, there is no reason to create multiple threads, that's why I referred to the windows service as being single threaded.

What I am worried about is that if somebody stops the service via the management console, it might be just during that 10 seconds of work the service is occasionally doing.

I have done some reading on SO and how to stop a service, but am a bit lost. Sometimes WorkerThreads are created, sometimes ManualResetEvents are created, but up to now I couldn't fully grasp the best way forward for my windows service.

I am thinking that I need to check during the 10 seconds execution some sort of flag and then only continue if that flag isn't telling me that I should stop. And in the onStop method I probably need to wait until the processing is properly finished.

So much for the theory ;) , but what is my best way forward then, also considering the code snippet below?

Thanks all!

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
Was it helpful?

Solution

Just take the lock so that OnStop() cannot run at the same time as Elapsed event handler:

   Protected Overrides Sub OnStop()
       SyncLock Me
           _timer.Stop()
       End SyncLock
   End Sub

Which can race, the Elapsed event handler might already be scheduled to run but didn't yet enter the lock. So verify that the timer is still enabled:

   Private Sub _timer_Elapsed(ByVal sender As Object, ByVal e As EventArgs)
       SyncLock Me
           If Not _timer.Enabled Return
           '' etc..

Favor a dedicated lock object instead of Me. And watch out for the 30 seconds that the service controller is willing to wait before giving up, you are getting close.

Licensed under: CC-BY-SA with attribution
Not affiliated with StackOverflow
scroll top