Using System.Threading.Timer (SOS!)

L

Lauren Quantrell

I have just put together a vb.net app and now need to provide it to
users. This application needs to run the code in a sub every 60
seconds from a Windows Service application. I have the functionality
of the sub working fine but I cannot figure out how to run the timer.

The sub DoSomethingHere() needs to run every 60 seconds. It doesn't
need to change the interval or anything like that. It just needs to
run every 60 seconds as long as the service is running.

I have never used a timer and my attempts to make this work haven't
worked.

I'm hoping someone can show me how to do this in a Windows Service app
in vb.net.

Much Thanks!
lq

System.Threading.Timer code from MSDN:

'Start Code:


Imports Microsoft.VisualBasic
Imports System
Imports System.Threading

Public Class TimerExample

Shared Sub Main()

Dim autoEvent As New AutoResetEvent(False)
Dim statusChecker As New StatusChecker(10)

' Create the delegate that invokes methods for the timer.
Dim timerDelegate As TimerCallback = _
AddressOf statusChecker.CheckStatus

' Create a timer that signals the delegate to invoke
' CheckStatus after one second, and every 1/4 second
' thereafter.
Console.WriteLine("{0} Creating timer." & vbCrLf, _
DateTime.Now.ToString("h:mm:ss.fff"))
Dim stateTimer As Timer = _
New Timer(timerDelegate, autoEvent, 1000, 250)

' When autoEvent signals, change the period to every
' 1/2 second.
autoEvent.WaitOne(5000, False)
stateTimer.Change(0, 500)
Console.WriteLine(vbCrLf & "Changing period." & vbCrLf)

' When autoEvent signals the second time, dispose of
' the timer.
autoEvent.WaitOne(5000, False)
stateTimer.Dispose()
Console.WriteLine(vbCrLf & "Destroying timer.")

End Sub
End Class

Public Class StatusChecker

Dim invokeCount, maxCount As Integer

Sub New(count As Integer)
invokeCount = 0
maxCount = count
End Sub

' This method is called by the timer delegate.
Sub CheckStatus(stateInfo As Object)
Dim autoEvent As AutoResetEvent = _
DirectCast(stateInfo, AutoResetEvent)
invokeCount += 1
Console.WriteLine("{0} Checking status {1,2}.", _
DateTime.Now.ToString("h:mm:ss.fff"), _
invokeCount.ToString())

If invokeCount = maxCount Then

' Reset the counter and signal to stop the timer.
invokeCount = 0
autoEvent.Set()
End If
End Sub

End Class
 
Z

zacks

I have just put together a vb.net app and now need to provide it to
users. This application needs to run the code in a sub every 60
seconds from a Windows Service application. I have the functionality
of the sub working fine but I cannot figure out how to run the timer.

The sub DoSomethingHere() needs to run every 60 seconds. It doesn't
need to change the interval or anything like that. It just needs to
run every 60 seconds as long as the service is running.

I have never used a timer and my attempts to make this work haven't
worked.

I'm hoping someone can show me how to do this in a Windows Service app
in vb.net.

Much Thanks!
lq

System.Threading.Timer code from MSDN:

'Start Code:

Imports Microsoft.VisualBasic
Imports System
Imports System.Threading

Public Class TimerExample

Shared Sub Main()

Dim autoEvent As New AutoResetEvent(False)
Dim statusChecker As New StatusChecker(10)

' Create the delegate that invokes methods for the timer.
Dim timerDelegate As TimerCallback = _
AddressOf statusChecker.CheckStatus

' Create a timer that signals the delegate to invoke
' CheckStatus after one second, and every 1/4 second
' thereafter.
Console.WriteLine("{0} Creating timer." & vbCrLf, _
DateTime.Now.ToString("h:mm:ss.fff"))
Dim stateTimer As Timer = _
New Timer(timerDelegate, autoEvent, 1000, 250)

' When autoEvent signals, change the period to every
' 1/2 second.
autoEvent.WaitOne(5000, False)
stateTimer.Change(0, 500)
Console.WriteLine(vbCrLf & "Changing period." & vbCrLf)

' When autoEvent signals the second time, dispose of
' the timer.
autoEvent.WaitOne(5000, False)
stateTimer.Dispose()
Console.WriteLine(vbCrLf & "Destroying timer.")

End Sub
End Class

Public Class StatusChecker

Dim invokeCount, maxCount As Integer

Sub New(count As Integer)
invokeCount = 0
maxCount = count
End Sub

' This method is called by the timer delegate.
Sub CheckStatus(stateInfo As Object)
Dim autoEvent As AutoResetEvent = _
DirectCast(stateInfo, AutoResetEvent)
invokeCount += 1
Console.WriteLine("{0} Checking status {1,2}.", _
DateTime.Now.ToString("h:mm:ss.fff"), _
invokeCount.ToString())

If invokeCount = maxCount Then

' Reset the counter and signal to stop the timer.
invokeCount = 0
autoEvent.Set()
End If
End Sub

End Class

This page:

http://msdn2.microsoft.com/en-us/library/zt39148a(VS.80).aspx

and then this page:

http://msdn2.microsoft.com/en-us/library/system.timers.timer(VS.80).aspx

is what I used to figure this out once.

Sorry, don't have the code available to post.
 
B

Branco Medeiros

Lauren said:
I have just put together a vb.net app and now need to provide it to
users. This application needs to run the code in a sub every 60
seconds from a Windows Service application. I have the functionality
of the sub working fine but I cannot figure out how to run the timer.

The sub DoSomethingHere() needs to run every 60 seconds. It doesn't
need to change the interval or anything like that. It just needs to
run every 60 seconds as long as the service is running.
<snip>

I didn't understand exactly what the thread must do: perform some action
then wait 60 seconds and repeat, or perform an action at each 60 seconds,
which would mean to spawn another thread if the previous one hadn't finished
yet (in case the thread activity lasts more than 60 seconds).

In the first case, the thread itself can control its inactivity (you don't
really need a timer). In the second case, it would be the job of a
controller thread to spawn new threads at each 60 secs... Also in this case
the controller thread itself could take care of the intervals between the
activity, you wouldn't need a timer also (or so it seems to me).

A simplistic approach would be for the worker (or controller) thread to just
call Sleep with the desired interval. The problem is that your service may
need to finish while the other thread is still sleeping, which would mean to
wait for the complete interval to ellapse and the thread to awake. Not a
good thing, if you ask me. Another possibility would be for the secondary
thread to wait on a controlled resource (say, a ManualResetEvent) with a
timeout for the current interval. Hack, I guess this is better shown than
explained...

<aircode>
'Use an event to get the appropriate interval
Public Class IntervalEventArgs
Inherits EventArgs
Public Property Interval() As Integer
End Property
End Class

'...
'In the class that controls the thread activity
'(your main class, probably)
Private WithEvents mWorker As Worker
Private mEvent As New ManualResetEvent(False)
Private mThread As Thread

Private Sub Worker_Interval( _
ByVal Sender As Object, _
ByVal E As IntervalEventArgs _
) Handles mWorker.Interval

E.Interval = 'Assign an appropriate interval

End Sub

Public Sub StartWorking()
'Creates the thread that will execute the work
If mWorker Is Nothing Then
mEvent.Reset()
mWorker = New Worker(mEvent)
mThread = New Thread(AddressOf mWorker.DoWork)
mThread.Start()
End If

End Sub

Public Sub StopWorking()
'Cancels the worker thread
If mWorker IsNot Nothing Then
Dim Temp As Worker = mWorker
mWorker = Nothing
Temp.Cancel = True

'If the worker is sleeping,
'this will bring it back
'from dream-land
mEvent.Set()

'waits for the thread to finish (hopefully)
'-- a timeout may be advised...
mThread.Join()

End If
End Sub

'...
'The worker class
Public Class Worker

Public Event Interval( _
ByVal Sender As Object, _
ByVal E As IntervalEventArgs)

Private mEvent As ManualResetEvent

Public Sub New(ByVal SourceEvent As ManualResetEvent)
mEvent = SourceEvent
End Sub

Public Property Cancel() As Boolean
'Allows a caller to cancel the thread operation
'in the middle of work -- must be checked by
'the thread periodically
End Property

Sub DoWork()
Dim Args As New IntervalEventArgs
Do
'starts getting the current interval from the
'main app
RaiseEvent Interval(Me, Args)

'waits or times-out (the expected behavior)
mEvent.WaitOne(Args.Interval, False)

If Cancel Then Exit Do

'... Do work
'... Don't forget to check Cancel
'... periodically!
Loop
End Sub
End Class
</aircode>

HTH.

Regards,

Branco.
(Rats, Google Groups seems to be down...)
 
L

Lauren Quantrell

<snip>

I didn't understand exactly what the thread must do: perform some action
then wait 60 seconds and repeat, or perform an action at each 60 seconds,
which would mean to spawn another thread if the previous one hadn't finished
yet (in case the thread activity lasts more than 60 seconds).

In the first case, the thread itself can control its inactivity (you don't
really need a timer). In the second case, it would be the job of a
controller thread to spawn new threads at each 60 secs... Also in this case
the controller thread itself could take care of the intervals between the
activity, you wouldn't need a timer also (or so it seems to me).

A simplistic approach would be for the worker (or controller) thread to just
call Sleep with the desired interval. The problem is that your service may
need to finish while the other thread is still sleeping, which would mean to
wait for the complete interval to ellapse and the thread to awake. Not a
good thing, if you ask me. Another possibility would be for the secondary
thread to wait on a controlled resource (say, a ManualResetEvent) with a
timeout for the current interval. Hack, I guess this is better shown than
explained...

<aircode>
'Use an event to get the appropriate interval
Public Class IntervalEventArgs
Inherits EventArgs
Public Property Interval() As Integer
End Property
End Class

'...
'In the class that controls the thread activity
'(your main class, probably)
Private WithEvents mWorker As Worker
Private mEvent As New ManualResetEvent(False)
Private mThread As Thread

Private Sub Worker_Interval( _
ByVal Sender As Object, _
ByVal E As IntervalEventArgs _
) Handles mWorker.Interval

E.Interval = 'Assign an appropriate interval

End Sub

Public Sub StartWorking()
'Creates the thread that will execute the work
If mWorker Is Nothing Then
mEvent.Reset()
mWorker = New Worker(mEvent)
mThread = New Thread(AddressOf mWorker.DoWork)
mThread.Start()
End If

End Sub

Public Sub StopWorking()
'Cancels the worker thread
If mWorker IsNot Nothing Then
Dim Temp As Worker = mWorker
mWorker = Nothing
Temp.Cancel = True

'If the worker is sleeping,
'this will bring it back
'from dream-land
mEvent.Set()

'waits for the thread to finish (hopefully)
'-- a timeout may be advised...
mThread.Join()

End If
End Sub

'...
'The worker class
Public Class Worker

Public Event Interval( _
ByVal Sender As Object, _
ByVal E As IntervalEventArgs)

Private mEvent As ManualResetEvent

Public Sub New(ByVal SourceEvent As ManualResetEvent)
mEvent = SourceEvent
End Sub

Public Property Cancel() As Boolean
'Allows a caller to cancel the thread operation
'in the middle of work -- must be checked by
'the thread periodically
End Property

Sub DoWork()
Dim Args As New IntervalEventArgs
Do
'starts getting the current interval from the
'main app
RaiseEvent Interval(Me, Args)

'waits or times-out (the expected behavior)
mEvent.WaitOne(Args.Interval, False)

If Cancel Then Exit Do

'... Do work
'... Don't forget to check Cancel
'... periodically!
Loop
End Sub
End Class
</aircode>

HTH.

Regards,

Branco.
(Rats, Google Groups seems to be down...)


Branco,
Thanks for the thorough explanation. I'll check this out.
 

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