windows (vb.net 1.1) service - threading issue

  • Thread starter brendan_gallagher_2001
  • Start date
B

brendan_gallagher_2001

Hi

I am seeing some strange behaviour on a windows (vb.net 1.1) service.
Basically, what I see happening is that when the Timer1_Elapsed event
fires, it attempts to execute Timer1.Stop() but takes a long time to
do this. In the meantime, the Timer1_Elapsed event fires again and a
new thread seems to try and also tries to execute Timer1.Stop().
Eventually, both threads manage to execute Timer1.Stop() and both
threads execute the DoSomething() method. Has anyone seen this
before? What can I do to prevent it?

Protected Overrides Sub OnStop()
' Add code here to perform any tear-down necessary to stop
your service.
Timer1.Enabled = False
End Sub

Private Sub Timer1_Elapsed(ByVal sender As System.Object, ByVal e
As System.Timers.ElapsedEventArgs) Handles Timer1.Elapsed
' stop the timer while the process runs
If Switch.TraceVerbose Then
Trace.WriteLine("Timer elapsed")
End If
Timer1.Stop()
DoSomething()
' restart the timer
Timer1.Start()
End Sub


Public Sub DoSomething()
If Switch.TraceVerbose Then
Trace.WriteLine("Executing DoSomething")
End If
 
J

Jason Keats

Hi

I am seeing some strange behaviour on a windows (vb.net 1.1) service.
Basically, what I see happening is that when the Timer1_Elapsed event
fires, it attempts to execute Timer1.Stop() but takes a long time to
do this. In the meantime, the Timer1_Elapsed event fires again and a
new thread seems to try and also tries to execute Timer1.Stop().
Eventually, both threads manage to execute Timer1.Stop() and both
threads execute the DoSomething() method. Has anyone seen this
before? What can I do to prevent it?

Protected Overrides Sub OnStop()
' Add code here to perform any tear-down necessary to stop
your service.
Timer1.Enabled = False
End Sub

Private Sub Timer1_Elapsed(ByVal sender As System.Object, ByVal e
As System.Timers.ElapsedEventArgs) Handles Timer1.Elapsed
' stop the timer while the process runs
If Switch.TraceVerbose Then
Trace.WriteLine("Timer elapsed")
End If
Timer1.Stop()
DoSomething()
' restart the timer
Timer1.Start()
End Sub


Public Sub DoSomething()
If Switch.TraceVerbose Then
Trace.WriteLine("Executing DoSomething")
End If


Here's some code I use to do some work at 01:15 each night. It may give
you some ideas.

Private mbBusy As Boolean
Private Timer1 As New System.Timers.Timer(60000)

Private Sub Timer1_Elapsed(ByVal pSender As Object, ByVal pArgs As
System.Timers.ElapsedEventArgs)

If mbBusy Then Exit Sub

Dim z As DateTime
Dim s As String = Format(z.Now, "HH:mm")

Select Case s
Case "01:15"

mbBusy = True
LogItem("BEGIN")

DoJob()

LogItem("END")
mbBusy = False

Case Else
'LogItem("ReviewService " & s)

End Select

End Sub

Protected Overrides Sub OnStart(ByVal args() As String)
' Add code here to start your service. This method should set things
' in motion so your service can do its work.

LogItem("ReviewService Started")

AddHandler Timer1.Elapsed, AddressOf Timer1_Elapsed
Timer1.Start()
Timer1.Enabled = True

End Sub

Protected Overrides Sub OnStop()
' Add code here to perform any tear-down necessary to stop your service.

Timer1.Enabled = False
Timer1.Stop()
RemoveHandler Timer1.Elapsed, AddressOf Timer1_Elapsed

LogItem("ReviewService Stopped")

End Sub


LogItem just appends some text to a (log) file. DoJob does the work I
want done. It seems to work okay.

HTH
 
B

brendan_gallagher_2001

Here's some code I use to do some work at 01:15 each night. It may give
you some ideas.

Private mbBusy As Boolean
Private Timer1 As New System.Timers.Timer(60000)

Private Sub Timer1_Elapsed(ByVal pSender As Object, ByVal pArgs As
System.Timers.ElapsedEventArgs)

        If mbBusy Then Exit Sub

        Dim z As DateTime
        Dim s As String = Format(z.Now, "HH:mm")

        Select Case s
                Case "01:15"

                        mbBusy = True
                        LogItem("BEGIN")

                        DoJob()

                        LogItem("END")
                        mbBusy = False

                Case Else
                        'LogItem("ReviewService "& s)

        End Select

End Sub

Protected Overrides Sub OnStart(ByVal args() As String)
        ' Add code here to start your service. This method shouldset things
        ' in motion so your service can do its work.

        LogItem("ReviewService Started")

        AddHandler Timer1.Elapsed, AddressOf Timer1_Elapsed
        Timer1.Start()
        Timer1.Enabled = True

End Sub

Protected Overrides Sub OnStop()
        ' Add code here to perform any tear-down necessary to stop your service.

        Timer1.Enabled = False
        Timer1.Stop()
        RemoveHandler Timer1.Elapsed, AddressOf Timer1_Elapsed

        LogItem("ReviewService Stopped")

End Sub

LogItem just appends some text to a (log) file. DoJob does the work I
want done. It seems to work okay.

HTH- Hide quoted text -

- Show quoted text -

Thanks Jason. Do you think there is anything I can do on the
threading side to prevent two threads executing the the DoSomething()
method at the same time?
 
B

brendan_gallagher_2001

Yes, put in a lock...

In your service class

Private Shared _lock As New Object()

In your DoSomething() Method:

Private Sub DoSomething ()
        SyncLock _lock ' only one thread at a time can enter here
                ' Do your cool stuff
        End SyncLock
End Sub

Thanks Tom. Is there any chance of a deadlock happening when using
SyncLock in this way?
 
B

brendan_gallagher_2001

It depends on what you do inside the lock...  If for some reason, a thread
enters the lock, and never exits - then yes, you could deadlock.

thanks again. Is there any way to avoid that happening i.e. kill the
thread after a certain lenght of time?
 
B

brendan_gallagher_2001

thanks again.  Is there any way to avoid that happening i.e. kill the
thread after a certain lenght of time?- Hide quoted text -

- Show quoted text -

I have just discovered that the Monitor class resolves this:


Public Sub Foo()
Dim sText As String
Dim objLock As Object = New Object()
Try
Monitor.Enter(objLock)
Try
sText = "Hello"
Finally
Monitor.Exit(objLock)
End Try
Catch e As Exception
MessageBox.Show(e.Message)
End Try
End Sub
 
B

Brian Gideon

thanks again.  Is there any way to avoid that happening i.e. kill the
thread after a certain lenght of time?

The best way to prevent that is to avoid calling methods that may
block. If a method has a reasonable chance of blocking see if there
is an overload that accepts a timeout parameter or use an asynchronous
version of the operation. If neither of those options exist then you
may to execute the operation in separate thread that can be terminated
if necessary. Be careful when waiting on a WaitHandle inside a lock.
That is a very common situation that can cause a deadlock.

Another common cause for deadlocks is acquiring locks out of order.
Consider the following example:

' Thread #1
SyncLock A
SyncLock B
End SyncLock
End SyncLock

' Thread #2
SyncLock B
SyncLock A
End SyncLock
End SyncLock

Eventually these two threads will deadlock. Why? Because they are
attempting to acquire locks in a different order. Solution: don't do
that.
 

Ask a Question

Want to reply to this thread or ask your own question?

You'll need to choose a username for the site, which only take a couple of moments. After that, you can post your question and our members will help you out.

Ask a Question

Top