Are Threading.Timers Supposed to be Accurate?

  • Thread starter Thread starter Charles
  • Start date Start date
C

Charles

Perhaps I have misunderstood how these things work. I have a Threading.Timer
object set to go off every 10 seconds. The timer callback sends some data
out on a TCP socket and checks for a reply. It then terminates. It will only
wait for a maximum of 5 seconds, but occasionally it will timeout and exit.

If the first callback occurs at time t and takes 5 seconds to complete, I am
expecting the next callback to occur at t+10. That's correct, isn't it?

What I am finding is that sometimes a callback doesn't occur for as much as
22 seconds after the previous one. What could cause this?

Would a System.Timers.Timer be any better?

TIA

Charles
 
Hi Michael

Thanks for the reply.
your first scenario simply can't happen (t+5) for a 10 second timer. Your

I meant that the callback takes 5 seconds to do its work, but below I have
seen teh callback report 5 seconds.

Here's the code

' Create timer
m_Timer = New Threading.Timer(AddressOf TimerCallback, New TimerState,
10000, 10000)

And the TimerCallback function is

Private Sub PollCallback(ByVal state As Object)

SyncLock Me
Try
Dim TimeNow As DateTime = Now

ts = DirectCast(state, TimerState)

If Not ts.FirstTime Then
Dim ElapsedSeconds As Long =
DateDiff(DateInterval.Second, ts.LastCalled, TimeNow)

If ElapsedSeconds < 9 Then
' Called too quickly
OnTimerError(String.Format("Timer Request queued too
quickly, in {0} seconds", ElapsedSeconds))

ElseIf ElapsedSeconds > 11 Then
' Called too slowly
OnTimerError(String.Format("Timer Request queued too
slowly, in {0} seconds", ElapsedSeconds))
End If
End If

ts.LastCalled = TimeNow ' assignment clears FirstTime
flag

' Do stuff that takes 1 to 5 seconds

End SyncLock

End Sub

Sometimes it reports 5 seconds, sometimes 14, sometimes 25. Mostly it
reports nothing.

There are other things going on in the app, but mostly just waiting on wait
handles for things to be signalled, like messages coming in. CPU never gets
abovre a few percent for the whole machine, running Windows Server 2003.

Charles
 
Charles said:
Sometimes it reports 5 seconds, sometimes 14, sometimes 25. Mostly it
reports nothing.

There are other things going on in the app, but mostly just waiting on wait
handles for things to be signalled, like messages coming in. CPU never gets
abovre a few percent for the whole machine, running Windows Server 2003.

Charles

It must be somewhere else in your code. The following code "never" (running
for several minutes) shows the issue you describe, and is based off the code
provided:

Module Module1
Public Class TimerState
Public LastCalled As DateTime
Public FirstTime As Boolean
Sub New()
FirstTime = True
End Sub
End Class
Public Class TimerContainer
Private m_Timer As Threading.Timer
Private Sub PollCallback(ByVal state As Object)
SyncLock Me
Try
Console.WriteLine("HERE")
Dim TimeNow As DateTime = Now
Dim ts As TimerState = DirectCast(state, TimerState)
If Not ts.FirstTime Then
Dim ElapsedSeconds As Long = DateDiff(DateInterval.Second,
ts.LastCalled, TimeNow)
If ElapsedSeconds < 9 Then
' Called too quickly
OnTimerError(String.Format("Timer Request queued too quickly, in {0}
seconds", ElapsedSeconds))
ElseIf ElapsedSeconds > 11 Then
' Called too slowly
OnTimerError(String.Format("Timer Request queued too slowly, in {0}
seconds", ElapsedSeconds))
End If
End If
ts.LastCalled = TimeNow ' assignment clears FirstTime flag()
' Do stuff that takes 1 to 5 seconds
LongProcedure()
Catch
End Try
End SyncLock
End Sub
Sub LongProcedure()
Dim sw As New Stopwatch
sw.Start()
Dim r As New Random
Dim n As Integer = 40000000
Dim numbers As New List(Of Integer)
For i As Integer = 1 To n
numbers.Add(r.Next(0, n))
Next
numbers.Sort()
Console.WriteLine(sw.ElapsedMilliseconds)
End Sub
Sub OnTimerError(ByVal msg As String)
Console.WriteLine(msg)
End Sub
Public Sub New()
m_Timer = New Threading.Timer(AddressOf PollCallback, New TimerState,
10000, 10000)
End Sub
End Class
Sub Main()
Dim tc As New TimerContainer()
Console.WriteLine("waiting...")
Console.ReadKey(True)
End Sub
End Module


Mike
 
Hi Mike

I think I have found the cause of the problem: the server is running Backup
Exec, and it had amassed itself a virtual memory size of 22 Gb, with a
working set of 14 Gb, on a machine with 16 Gb physical memory. I can only
assume that it was causing things to freeze for many seconds and that pushed
the timer over the edge.

I have restarted the BE services and its footprint is down to 0.8 Gb and a
working set of just 0.4 Gb. Everything seems to be back to normal again,
touch wood.

Cheers

Charles
 
Hi Mike

You might see from my reply to the other Mike that I think I have found the
problem. I didn't have much respect for BE before I started, and now it has
plummeted!

Anyway, all good now, I think, and I will change the SyncLock statement as
well.

Cheers

Charles
 
Back
Top