-
Dec 29th, 2014, 04:51 PM
#1
Thread Starter
Lively Member
[RESOLVED] Threading.Timer and Thread.Sleep - unexpected interaction
All,
Following is a simplified snippet from a program I am currently developing:
Imports System.Threading
Code:
Public Class myClass
Dim bIsRunning As Boolean = False
Dim myTimer As Threading.Timer
Private Sub btn_Click(sender As System.Object, e As System.EventArgs) Handles btn.Click
If Not bIsRunning Then
bIsRunning = True
myTimer = New Threading.Timer(AddressOf myTimer_Tick, Nothing, 0, Timeout.Infinite)
Else
bIsRunning = False
Thread.Sleep(3000)
myTimer.Dispose()
myTimer = Nothing
End If
End Sub
Private Sub myTimer_Tick(ByVal state As Object)
<do stuff, including updating the form on which btn resides>
If bIsRunning Then
waitTime = <calculate value>
myTimer.Change(waitTime, Timeout.Infinite)
End If
End Sub
End Class
While this approach is not ideal (none of my attempts with various locking mechanisms worked well), this does get the job done. But. For some reason that i do not understand, the Thread.Sleep() call in Btn_Click causes myTimer_Tick to sleep as well. I have verified this by inserting Console.Write statements into myTimer_Tick.
I was under the impression that the Threading.Timer ran in its own thread, thus a Thread.Sleep in the parent thread should not affect it. Obviously, my impression is wrong. Can you please a) point me to something that explains this behavior and b) suggest an approach that obviates this problem.
Thank you.
-
Dec 29th, 2014, 09:10 PM
#2
Fanatic Member
Re: Threading.Timer and Thread.Sleep - unexpected interaction
Hi,
I couldnt be certain but I think you need to create a new thread to run the timer on otherwise it runs on the UI thread. Make a new thread and in that create your timer, see what happens.
My CodeBank Submissions
- Listbox with transparency and picture support - Click Here
- Check for a true internet connection - Click Here
- Open Cash drawer connected to receipt printer - Click Here
- Custom color and size border around form - Click Here
- Upload file to website without user logins, includes PHP - Click Here
- List All Removable USB Storage Devices - Click Here
- Custom On/Off Slide Control - Click Here
- Insert multiple rows of data into one database table using parameters - Click Here
- Trigger USB/Serial Cash Drawer - Click Here
-
Dec 30th, 2014, 12:19 AM
#3
Re: Threading.Timer and Thread.Sleep - unexpected interaction
Actually, to be honest, I think the timer DOES run on a secondary thread... the blocking comes from the Tick event which is handled on the main UI Thread, which is currently sleeping due to the Thread.Sleep command.
Think of the thread.sleep as Developer.Sleeping ... even though the AlarmClock_AlarmSounds event happens, because the Developer.Sleeping is in effect, the event is ignored.
-tg
-
Dec 30th, 2014, 12:22 AM
#4
Thread Starter
Lively Member
Re: Threading.Timer and Thread.Sleep - unexpected interaction
bensonsearch,
Thank you for the reply. Your suggestion seemed like a good one - in fact, my code originally had a thread (but I got rid of it because I thought the timer ran in its own thread). However, since you suggested this, I put it back into my code - which now looks like the following:
Code:
Public Class myClass
Dim bIsRunning As Boolean = False
Dim trd As Thread
Dim myTimer As Threading.Timer
Private Sub btn_Click(sender As System.Object, e As System.EventArgs) Handles btn.Click
If Not bIsRunning Then
bIsRunning = True
trd = New Thread(AddressOf trdThread)
trd.Start()
Else
bIsRunning = False **
Thread.Sleep(3000)
myTimer.Dispose()
myTimer = Nothing
trd.Abort()
trd = Nothing
End If
End Sub
Sub trdThread()
myTimer = New Threading.Timer(AddressOf myTimer_Tick, Nothing, 0, Timeout.Infinite)
End Sub
Private Sub myTimer_Tick(ByVal state As Object)
<do stuff, including updating the form on which btn resides>
If bIsRunning Then
waitTime = <calculate value> **
myTimer.Change(waitTime, Timeout.Infinite)
End If
End Sub
End Class
Sadly, the issue remains - the Thread.Sleep call in btn_Click causes myTimer_Tick to sleep as well. (This has been confirmed with Console.Write statements at each of the two locations marked **. If the Thread.Sleep had no impact on myTimer_Tick, there should be no delay between the two Console.Write statements. However, the delay is equal to the Thread.Sleep time, thus the Thread.Sleep call in btn_Click causes myTimer_Tick to sleep.)
This is getting very frustrating as this should be easy and I don't know what I am doing wrong.
Last edited by groston; Dec 30th, 2014 at 12:29 AM.
-
Dec 30th, 2014, 12:33 AM
#5
Thread Starter
Lively Member
Re: Threading.Timer and Thread.Sleep - unexpected interaction
techgnome,
Thank you.
Assuming you are correct, this seems like odd behavior. Why would the Tick event be handled in the UI thread? If you look at my second post (which was being written at the same time as your post), the Tick event seems to be handled by the UI thread even when the timer is launched from a secondary thread.
How can I get the Tick handler out of the UI thread?
-
Dec 30th, 2014, 08:16 AM
#6
Re: Threading.Timer and Thread.Sleep - unexpected interaction
The code in your Sub myTimer_Tick will be running on a different thread from the code in Sub btn_Click.
I think you are using the timer in a somewhat unusual manner, and this is why you are having problems.
This line:
Code:
myTimer = New Threading.Timer(AddressOf myTimer_Tick, Nothing, 0, Timeout.Infinite)
is creating a Threading.Timer with a "due time" of 0 milliseconds, and a "period" of Timeout.Infinite.
This means the callback delegate will be invoked just the once, immediately ("due time" = 0) but then never invoked again ("period" = Timeout.Infinite).
However, the callback code has this line:
Code:
myTimer.Change(waitTime, Timeout.Infinite)
where you reset the "due time" but leave the "period" unchanged.
This means the callback delegate will be invoked again, just the once, after waitTime milliseconds ("due time" = waitTime), but then never invoked again ("period" = Timeout.Infinite).
Of course, when it is actually invoked after waitTime milliseconds, the myTimer.Change line of code is executed again, the "due time" is set again, and the callback will be invoked again, just the once, after waitTime milliseconds. And on we go....
So your timer is acting like a Timer, but it's your code that is causing it to tick after you manually reset the "due time". It's not repeatedly ticking automatically.
So why's it failing immediately after you set your UI thread to sleep for 3 seconds? Well, at the same time you set Thread.Sleep(3000), you also set bIsRunning = False, and this global boolean acts in your callback sub (Sub myTimer_Tick) to stop the resetting of the "due time". So when blIsRunning is False, the callback code is not invoked anymore.
If you want the timer to keep "ticking" while the UI thread sleeps, try moving bIsRunning = False to the last line of the Else... End If block.
That said, given that you say you are updating the UI in the timer callback, I don't understand why you want to keep the timer running while the UI thread sleeps.
-
Dec 30th, 2014, 10:31 AM
#7
Re: Threading.Timer and Thread.Sleep - unexpected interaction
That said, given that you say you are updating the UI in the timer callback, I don't understand why you want to keep the timer running while the UI thread sleeps.
Not only that, if he really is running his timers in secondary threads, he'll get (appropriately) cross-thread exception calls (or at least should) - unless they are appropriately invoked (which we don't know since that part was taken out).
So there may be bigger issues.
-tg
-
Dec 30th, 2014, 07:04 PM
#8
Thread Starter
Lively Member
Re: Threading.Timer and Thread.Sleep - unexpected interaction
All,
Thanks for the replies.
With regard to the manner in which I am calling timer: The Tick routine can take a large amount of time as compared to the period. I just did an experiment comparing the method shown here (adjusting due time) versus simply setting the value for the period. It turns our that the approach used here is far more accurate (in terms of maintaining the specified time between ticks). Thus, while seemingly odd looking, this actually works well. The author of this post, http://stackoverflow.com/questions/1...mer-in-c-sharp, seems to advocate a similar approach.
With regard to the comment about moving the bIsRunning line: That will not work. The thing to remember is that the Tick event can get queued for execution, and if one disposes the timer (which, under this scenario would happen before the Tick is told to stop ticking) while a Tick is queued for execution, an error is thrown. (My apologies if the explanation is not spot on, but I have seen this error more than once while working on this.)
With regard to cross-thread calls: The real code does use delegates/invoke and this has not been a problem.
What I seem to have 'discovered' is that when Tick handler is in a separate class, it does seem to execute in a different thread from the UI.
Last edited by groston; Dec 30th, 2014 at 07:09 PM.
-
Dec 30th, 2014, 08:51 PM
#9
Re: Threading.Timer and Thread.Sleep - unexpected interaction
Originally Posted by groston
All,
I was under the impression that the Threading.Timer ran in its own thread, thus a Thread.Sleep in the parent thread should not affect it. Obviously, my impression is wrong. Can you please a) point me to something that explains this behavior and b) suggest an approach that obviates this problem.
Thank you.
But you are not wrong...
-
Dec 31st, 2014, 07:29 AM
#10
Re: Threading.Timer and Thread.Sleep - unexpected interaction
I would expect that the timer tick code can be blocked if the UI thread has executed the sleep. Lets say that right before the tick is going to happen the button is pressed. It puts the UI to sleep for three seconds. Then the tick occurs and tries to update the UI but it can't because the UI is sleeping, so it has to wait. Eventually the sleep expires and then you dispose of the timer which may or may not affect the currently active tick.
-
Dec 31st, 2014, 11:48 AM
#11
Thread Starter
Lively Member
Re: Threading.Timer and Thread.Sleep - unexpected interaction
dbasnett,
Thank you! I think you figured out the problem. It is not the Sleep in the UI Thread, per se, that is the problem, but rather the call to update the UI from the timer thread that is the problem. This 'second order' interaction had not occurred to me.
FYI: My comment about having code in two classes was completely wrong - sorry.
-
Dec 31st, 2014, 04:23 PM
#12
Re: Threading.Timer and Thread.Sleep - unexpected interaction
Your problem is you use sleep. Why do you waste our time with comments like you handle UI invoking yet not show it.
What I seem to have 'discovered' is that when Tick handler is in a separate class, it does seem to execute in a different thread from the UI.
Are you serious? the threading.timers class raises it's tick event regardless on a seperate thread thats not the ui :/
-
Dec 31st, 2014, 04:25 PM
#13
Re: Threading.Timer and Thread.Sleep - unexpected interaction
Take a deep breath and ask for help with a full explanation. You don’t really know what you are saying.
Tags for this Thread
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
|