|
-
Nov 4th, 2009, 05:09 AM
#1
Thread Starter
Lively Member
How to use system.threading.timer
I have used system.timers.timer to watch several folders and move files in my windows service. But the timer event stops now and then. I have read that it is better to use system.threading.timer in services.
This is my system.timers.timer code:
Private Timer As New System.Timers.Timer
AddHandler Timer.Elapsed, New System.Timers.ElapsedEventHandler(AddressOf Me.Timer_Elapsed)
Timer.Interval = 4000
Timer.Start()
Private Sub Timer_Elapsed(ByVal sender As System.Object, ByVal e As System.Timers.ElapsedEventArgs)
' do my code here!
End Sub
How do this code look like in system.threading.timer?
How do i start and stop the timer using threading? That is very important because i stop the timer when it comes to the elapsed event and when the code har run it starts the timer again!
/Patrik
-
Nov 4th, 2009, 06:03 AM
#2
Re: How to use system.threading.timer
Here's a simple example of how to use the Threading.Timer:
vb.net Code:
Imports System.Threading Public Class Form1 Private alarm As Threading.Timer Private Sub Form1_Load(ByVal sender As System.Object, ByVal e As System.EventArgs) Handles MyBase.Load Me.alarm = New Threading.Timer(AddressOf Tick, _ Nothing, _ CInt(Me.NumericUpDown1.Value), _ CInt(Me.NumericUpDown1.Value)) End Sub Private Sub Tick(ByVal state As Object) Console.WriteLine("Tick: " & Date.Now) End Sub Private Sub Button1_Click(ByVal sender As System.Object, ByVal e As System.EventArgs) Handles Button1.Click 'Stop the Timer. Me.alarm.Change(Timeout.Infinite, Timeout.Infinite) End Sub Private Sub Button2_Click(ByVal sender As System.Object, ByVal e As System.EventArgs) Handles Button2.Click 'Start or update the Timer. Me.alarm.Change(CInt(Me.NumericUpDown1.Value), CInt(Me.NumericUpDown1.Value)) End Sub End Class
Note that I use the Value from a NumericUpDown twice in many places there but you wouldn't always use the same value twice. The first time is the time before the first callback and the second is the time between callbacks after that.
-
Nov 4th, 2009, 06:05 AM
#3
Re: How to use system.threading.timer
I should also point out that the System.Timers.Timer is just a wrapper for the System.Threading.Timer so I don't see why one would work where the other doesn't.
-
Nov 4th, 2009, 09:01 AM
#4
Thread Starter
Lively Member
Re: How to use system.threading.timer
Thank you for your answers! I don't know exactly why the system.timers.timer wont' work any good in services, but i have read it on several forums!
I'll try this code!
-
Nov 4th, 2009, 09:23 AM
#5
Frenzied Member
Re: How to use system.threading.timer
JMC ... thanks for the example. But I have a couple questions:
1) Does the code you put in the Tick sub run in its own thread?
2) How do I update the UI in the Tick sub without getting a cross-threading error?
I just want to display the current time in a label for example.
Thanks...
-
Nov 4th, 2009, 10:17 AM
#6
Re: How to use system.threading.timer
Why would you have a UI at all if this is a Windows Service?
-
Nov 4th, 2009, 10:21 AM
#7
Frenzied Member
Re: How to use system.threading.timer
Good catch. Actually I just pasted the code snippet above into a new WinForm project to try it. Is the System.Timers.Timer & System.Threading.Timer only used for services?
-
Nov 4th, 2009, 10:40 AM
#8
Re: How to use system.threading.timer
Well no not ONLY, you can use them in a winforms project if you want but in a winforms project you would generally use the Windows.Forms.Timer component to avoid such threading issues
-
Nov 4th, 2009, 10:48 AM
#9
Frenzied Member
Re: How to use system.threading.timer
OK, so suppose I wanted to run a piece of code in its own thread at an interval and also update a label on the form ... which timer would be most appropriate?
-
Nov 4th, 2009, 01:32 PM
#10
Re: How to use system.threading.timer
Well if you do specifically want it to run on a background thread then the Systems.Threading.Timer is probably the easiest way of doing it. Then you would have to just use Delegates to update the UI (look at JMC's article in the codebank titled "accessing controls from worker threads").
Alternatively you could use the Windows.Forms.Timer and just kick off a new background thread each time the tick event is raised but there's not really much point as you would still have to do the same thing to update the UI from this background thread
-
Nov 4th, 2009, 05:09 PM
#11
Re: How to use system.threading.timer
 Originally Posted by nbrege
Does the code you put in the Tick sub run in its own thread?
From the documentation for the System.Threading.Timer:
Use a TimerCallback delegate to specify the method you want the Timer to execute. The timer delegate is specified when the timer is constructed, and cannot be changed. The method does not execute on the thread that created the timer; it executes on a ThreadPool thread supplied by the system.
If you use the System.Timers.Timer then the Elapsed event can be raised in the UI thread or a ThreadPool thread, depending on whether you set the SynchronizingObject property or not. The System.Windows.Forms.Timer always raises its Tick event on the UI thread.
-
Nov 9th, 2009, 02:36 AM
#12
Thread Starter
Lively Member
Re: How to use system.threading.timer
I use this code with my system.threading.timer, but something is wrong!
The timer seems to fire but occationally the code in the timer gets an error.. This error never came with system.timers.timer so i wonder if this code is right?
Imports System
Imports System.IO
Imports System.Threading
Public Class PDFmoverOT
Private Timer1 As System.Threading.Timer
Private Const TimerDelay As Long = 4000
Protected Overrides Sub OnStart(ByVal args() As String)
Dim autoEvent As New AutoResetEvent(False)
Dim timerDelegate As TimerCallback = AddressOf Timer1_Tick
Timer1 = New Timer(timerDelegate, autoEvent, 0, TimerDelay)
End Sub
Private Sub Timer1_Tick(ByVal stateInfo As Object)
' I want to stop the timer until my code is finished!
Call Timer1.Change(Timeout.Infinite, Timeout.Infinite)
'Do my code here
' Start the timer again!
Call Timer1.Change(TimerDelay, TimerDelay)
End Sub
End Class
-
Nov 9th, 2009, 03:08 AM
#13
Re: How to use system.threading.timer
If only we knew what the error message was, we might be able to help.
-
Nov 9th, 2009, 03:46 AM
#14
Thread Starter
Lively Member
Re: How to use system.threading.timer
Ok, i'll try to explain. I have 2 services that watches one folder for PDF files. I have defined what files wich service will move.. Each service reads it owns settings from an XML file!
Service 1 should only move files that begins with:
VB
VM
VS
And Service 2 should only move files that begins with:
JC
JT
The problem is that service 2 occationally tries to take service 1 files, but service one already has moved the file to the completed map and therefore service 2 complains that it can't find the file.. But this is so strange because i have defined that service 2 shouldn't take those files.. When i used system.timers,timer this problem never occured..
When the error occur the debug will complain on this line:
"If patterns.Count > 0 And FileIO.FileSystem.GetFileInfo(fName).Length > 5000 Then"
I have zipped the code of the services and the XML files and you can download it from here:
http://www.botnia.org/threading.zip
-
Nov 9th, 2009, 04:14 AM
#15
Re: How to use system.threading.timer
Just tell us what the error message is... not many people are going to want to download and run and test your code, but plenty of people will probably be able to help if you just tell us what the error message says
-
Nov 9th, 2009, 04:24 AM
#16
Thread Starter
Lively Member
Re: How to use system.threading.timer
Well as i wrote it complains over that service 2 can't find the file! And that is because service 1 already has moved the file to the completed folder. Service 2 shouldn't do anything about service 1 files, and this have worked all the time, but when i started using system.threading.timer this problem started!
When you dump files in the "watched" folder everything can work fine the first time, but when you dumps the same files for example for the third time the error occurs!??
That's why i'm wondering if my code in the first thread is right?
/Patrik
-
Nov 9th, 2009, 04:26 AM
#17
Thread Starter
Lively Member
Re: How to use system.threading.timer
i ment in the first thread posted today
-
May 9th, 2013, 01:29 AM
#18
Lively Member
Re: How to use system.threading.timer
Sorry to resurrect an old thread, but I googled and this was the best example I could find on the net. The problem I'm having is when I use this code:
Code:
WebWindow.StartCountDownTimer()
'PROXY; LOOP THAT KEEPS CHECKING UNTIL IP HAS CHANGED BEFORE RESTART TO NEW PAGE
Do While CurrentIP = PublicIP
Call DOIT()
Loop
Me.Text = PublicIP
WebWindow.Close()
When my code reaches this point and executes the Do While loop, my Timer stops. If what I'm reading and understanding in this thread is correct, then timers run on separate threads. Does that mean there is no way to make my timer count down in form2 (i.e. "WebWindow") when the Do While loop waits for the IP to change? FYI, I tried putting, "WebWindow.StartCountDownTimer()" inside my Do While loop, but it did not count down at all inside the Do While loop. Outside the loop, it counted down two or three seconds then stopped waiting for the Do While loop to end, then once the loop ended, the timer did not start again. Before I added the Do While loop, the timer worked perfectly.
-
May 9th, 2013, 02:08 AM
#19
Re: How to use system.threading.timer
 Originally Posted by Taem
Sorry to resurrect an old thread, but I googled and this was the best example I could find on the net. The problem I'm having is when I use this code:
Code:
WebWindow.StartCountDownTimer()
'PROXY; LOOP THAT KEEPS CHECKING UNTIL IP HAS CHANGED BEFORE RESTART TO NEW PAGE
Do While CurrentIP = PublicIP
Call DOIT()
Loop
Me.Text = PublicIP
WebWindow.Close()
When my code reaches this point and executes the Do While loop, my Timer stops. If what I'm reading and understanding in this thread is correct, then timers run on separate threads. Does that mean there is no way to make my timer count down in form2 (i.e. "WebWindow") when the Do While loop waits for the IP to change? FYI, I tried putting, "WebWindow.StartCountDownTimer()" inside my Do While loop, but it did not count down at all inside the Do While loop. Outside the loop, it counted down two or three seconds then stopped waiting for the Do While loop to end, then once the loop ended, the timer did not start again. Before I added the Do While loop, the timer worked perfectly.
What type of Timer is it: Windows.Forms.Timer, Timers.Timer or Threading.Timer? What's in your DOIT method?
Timers don't "run" on any thread. A Windows.Forms.Timer raises its Tick event on the UI thread. A Timers.Timer raises its Elapsed event on a ThreadPool thread by default but can raise it on the UI thread if you set its SynchronizingObject property. A Threading.Timer invokes its callback method on a ThreadPool thread.
-
May 9th, 2013, 10:26 AM
#20
Lively Member
Re: How to use system.threading.timer
What type of Timer is it: Windows.Forms.Timer, Timers.Timer or Threading.Timer?
I'm not entirely sure. It's base off a timer on Form2, so I suppose it's a form based timer. Here's the code for the timer:
Code:
Public Class WebWindow
Private Sub WebBrowser1_DocumentCompleted(sender As System.Object, e As System.Windows.Forms.WebBrowserDocumentCompletedEventArgs) Handles WebBrowser1.DocumentCompleted
End Sub
Private CD As Integer = 120
Private Sub Timer1_Tick(sender As System.Object, e As System.EventArgs) Handles Timer1.Tick
Me.lblCD.Text = ("NEXT SURVEY STARTS IN " & CD.ToString("00"))
If CD = 0 Then
Me.Timer1.Enabled = False
Else
CD -= 1
End If
End Sub
Public Sub StartCountDownTimer()
Timer1.Interval = 1000
Timer1.Start()
End Sub
End Class
What's in your DOIT method?
DOIT checks the users WAN (public IP); here's the relevant bits of code:
Code:
Imports System.Net
Imports System.IO
Public Class Form1
Dim PublicIP As String
Dim CurrentIP As String
Private Sub DOIT()
Dim client As New WebClient
'// Add a user agent header in case the requested URI contains a query.
client.Headers.Add("user-agent", "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.2; .NET CLR1.0.3705;)")
Dim baseurl As String = "http://checkip.dyndns.org/"
' with proxy server only:
Dim proxy As IWebProxy = WebRequest.GetSystemWebProxy()
proxy.Credentials = CredentialCache.DefaultNetworkCredentials
client.Proxy = proxy
Dim data As Stream
Try
data = client.OpenRead(baseurl)
Catch ex As Exception
MsgBox("open url " & ex.Message)
Exit Sub
End Try
Dim reader As StreamReader = New StreamReader(data)
Dim s As String = reader.ReadToEnd()
data.Close()
reader.Close()
s = s.Replace("<html><head><title>Current IP Check</title></head><body>", "").Replace("</body></html>", "").ToString()
PublicIP = s
End Sub
Private Sub btnPopulate_Click(ByVal sender As System.Object, ByVal e As System.EventArgs) Handles btnPopulate.Click
'(code that starts a For/Next loop)
Call DOIT()
Me.Text = PublicIP
CurrentIP = PublicIP
'(more code that starts a Try)
WebWindow.StartCountDownTimer()
'FOR PROXY; LOOP THAT KEEPS CHECKING UNTIL IP HAS CHANGED BEFORE CONTINUING CODE
Do While CurrentIP = PublicIP
Call DOIT()
Loop
Me.Text = PublicIP
WebWindow.Close()
Catch ex As NullReferenceException
'Swallow the exception and continue.
End Try
Next
End Sub
End Class
In a nutshell, the Do/While loop calls DOIT to see WHEN the IP changes before continuing the program. Works great. But it completely stops the timer (which worked before I added the Do/While loop).
-
May 9th, 2013, 10:39 AM
#21
Re: How to use system.threading.timer
It probably doesn't stop the timer, it just blocks it. Your loop is fully occupying the UI thread until it completes. Your timer also appears to be a Windows.Forms.Timer, because if you don't know then that's what it is. After all, to make any of the other timers you'd have to do it deliberately. To use a Windows.Forms.Timer you'd just drag the component onto the form. You can check this by going into the .designer.vb file and looking for your timer declaration, which will be in there, but it's a Forms.Timer.
Since it is a Forms.Timer, it will be raising events on the UI thread that you would hande in your Tick event handler, but only if the UI thread has a chance to pump messages. You don't give it a chance to pump messages while your loop is running because the loop is occupying all of its time. Theoretically, you could use one of the other timers such that the tick event is not occuring on the UI thread and wouldn't be blocked. However, I see that the ONLY reason you are using the timer is to show a countdown on the UI, so if you use a different timer you will have to synchronize back to the UI thread via Invoke, anyways. Therefore, I'd be inclined to say that you should just add an Application.DoEvents line into your loop and be done with it. The re-entrancy issues that some people object to with DoEvents isn't going to matter for this situation, so DoEvents will work....as poorly as anything else.
The problem is that your loop appears to make a few calls that might, themselves take longer than a second. Therefore, adding DoEvents will cause the counter to happen, but it likely wouldn't appear smooth. More likely you'd see the number jump up a couple values, pause for a time, jump up a bit more, pause, jump again, and so on. You'd have to have the tick event being handled in a different thread to get smoother behavior, but then you'd not just have to invoke back to the UI thread, but you'd probably have to explicitly call lblCD.Refresh after setting the text, or you might not ever see a change, as the Paint event triggered by changing the text would be blocked by your Do Loop the same way that the timer.tick events are being blocked.
My usual boring signature: Nothing
 
Posting Permissions
- You may not post new threads
- You may not post replies
- You may not post attachments
- You may not edit your posts
-
Forum Rules
|
Click Here to Expand Forum to Full Width
|