How to Generate an Accurate Timer Tick

  • Thread starter Thread starter Charles
  • Start date Start date
Charles,

All non main threads runs on the background, mostly with less priority than
a foreground thread.
A threading threading timer runs then even on its own thread like a
threading.dispatcher timer, quiet new, is the one in use with WPF.

Just my idea from what you wrote.

However, I did you not see give any response on my advice to use a
windows.timer.timer?

I simply don't understand why you don't want to use that?

Cor
 
I'm going to attempt to answer this myself, as I've had an idea.

Rather than try to generate a reliable timer tick, that won't get
deferred when the system gets busy, how about generating a time-out
instead. I can think of two obvious ways of doing it:

1. Put the timed task on it's own thread and go to sleep for the timer
tick interval
2. Also on a separate thread, wait on a handle that never gets set, and
set the timeout to the timer tick interval

I don't know if both methods amount to the same thing, but I would be
interested in people's opinions.

In the first scenario, I spin up a dedicated thread on which I intend to
perform my timed activity at a regular interval. I immediately put the
thread to sleep for my elapsed time, wake up, perform my task and go
back to sleep. This continues forever.

In the second scenario, I create a ManualResetEvent and use WaitOne to
wait for it to be signalled. I set the timeout to my elapsed time again.
Each time the timeout expires I perform my task, and then go back to
waiting again.

In each case, does the technique behave differently from the way a timer
works? In particular, do either or both of them avoid WM_TIMER events?
Are either of these going to give me a more stable and reliable
interval, bearing in mind that I don't mind the interval generated being
+/-50%, but I don't want it to ever be +200%, for example?

I have tried both, and as techniques they work, but testing in the case
where the system is busy and the interval becomes extended is harder to
test empirically.

Charles

I'd say you'd be reinventing the wheel.

Unless you're doing *really* strange things, most (if not all) of the
out-of-the-box timers offer the funtionality you want. From what i've
gathered from the thread, you want a timer that's alerted *roughly*
(give or take *5* seconds) every 10 seconds.

Can you more clearly state what the actual problem is with those timers?
 
Hi Cor

Having read the article you posted the link to, I didn't read anything that
made me think the Timers.Timer was going to provide any real advantage over
the Threading.Timer, which I am currently using. Do they function
differently under the hood? I know it says that the System.Timers.Timer is a
wrapper around Win32 waitable timer objects, but it doesn't say exactly how
the Threading.Timer works.

It's not that I don't want to use it, just that I didn't see what I would
gain by switching.

Charles
 
Hi Willem

The problem is simply that the Threading.Timer that I am using at present
doesn't always raise an event when the designated 10 seconds has expired. It
nearly always does, 99.9% of the time, probably. But occasionally, the event
is delayed for some reason, and might not occur for 20 or even 30 seconds
after the previous event. It is most likely to happen when the system is
quite busy (Windows Server 2003 R2 x64), perhaps performing a lot of disk
I/O, or something like that.

Charles
 
Hi Willem

The problem is simply that the Threading.Timer that I am using at
present doesn't always raise an event when the designated 10 seconds has
expired. It nearly always does, 99.9% of the time, probably. But
occasionally, the event is delayed for some reason, and might not occur
for 20 or even 30 seconds after the previous event. It is most likely to
happen when the system is quite busy (Windows Server 2003 R2 x64),
perhaps performing a lot of disk I/O, or something like that.

Charles

Ok, now I see where your idea of the second scenario comes from.

using a separate thread with a ManualResetEvent like this

private ManualResetEvent _quitEvent = new ManualResetEvent(false);
void ThreadProc()
{
while (!_quitEvent.WaitOne(timeout))
{
// ...Whatever it is your task should do...
}
}

will do the trick.

As soon as it's timeslice comes up, and the event is not signalled, the
thread will move into the while loop. Assuming it runs on it's own
thread, it will at least get scheduled and run (at some point).

The more interesting part though is why this wouldn't work with the
already provided timers. I haven't looked at the internals, but it seems
logical that the threaded timer also uses some waitable object to do
it's task. So the same problems may arise when using the scenario above.

Is there anyway, indication, or way of logging of *what* is going on
when the delay appears? Is the "delayed event" you talk about
synchronized (i.e. are the handlers called through Control.Invoke())
with the main thread?
 
Hi Willem

Yes, that's exactly what I was thinking, and almost exactly what I tried.

The process that runs when the interval has elapsed currently runs on the
thread of the callback; I'm using the Threading.Timer.

It's hard to be certain what is happening when the delay occurs. It used to
happen when memory was short (caused by a memory leak in BackupExec, but
that's been sorted now). The server where this happens I connect to using
Remote Desktop. I can often cause the problem if I transfer a file from a
mapped local drive over RDP to the server. That's about as much as I've been
able to tell. I'm tempted to give the manual reset event thing a try though,
now that you've picked up on the same idea.

Charles
 
Thinking about it further, the downside of this approach is that the
interval between 'ticks' is not 10 seconds anymore. It is 10 seconds +
length of time task takes. Perhaps that's not the end of the world, but I
might have to factor that in somehow.

Charles
 
It is hard for me to imagine a scenario where conventional timer messages
will be delayed sufficiently long enough to cause trouble with your
application. 5-10 seconds is a huge window. If you really are seeing such
a problem, the only thing that I can imagine is something that is seriously
wrong. This certainly isn't something that I've seen. Have you tried
System.Threading.Timer instead -- this create a threaded timer? If this
doesn't work, I think you need to look more closely at your system to see
where the hog resides.

--
Richard Grier, Consultant, Hard & Software 12962 West Louisiana Avenue
Lakewood, CO 80228 303-986-2179 (voice) Homepage: www.hardandsoftware.net
Author of Visual Basic Programmer's Guide to Serial Communications, 4th
Edition ISBN 1-890422-28-2 (391 pages) published July 2004, Revised July
2006.
 
Charles explained on 5/22/2010 :
Thinking about it further, the downside of this approach is that the interval
between 'ticks' is not 10 seconds anymore. It is 10 seconds + length of time
task takes. Perhaps that's not the end of the world, but I might have to
factor that in somehow.

Charles
ThreadPool.QueueUserWorkItem :)
 
Thinking about it further, the downside of this approach is that the
interval between 'ticks' is not 10 seconds anymore. It is 10 seconds +
length of time task takes. Perhaps that's not the end of the world, but
I might have to factor that in somehow.

Charles

But this will always be a factor to consider, whatever scenario you
choose. You should ask yourself whether you want the signalling system
to have some form of reentrancy. In other words: Is it allowed to be
signalled while a previous signal is still being processed?

If yes, then the question should be: Is the order of processing the
signals relevant or not? If it's not, you can just start the task on a
separate thread, or queue it on the threadpool. If it is, you'll have to
setup some sort of queue, that processes the signals asynchroniously,
but in queued order.

If no, then there's little you can do about it. Either you make sure the
tasks finishes within the signalling time window (which may or may not
be possible, but will always be very tough to guarantee), or you give up
on reentrancy of the signal.
 
Hi Dick

It is the Threading.Timer that I am using. I'm as surprised as you that the
tick gets delayed as long as it does, but it does.

I think I mentioned at the outset that originally the problem was associated
with low memory, because of a memory leak in BackupExec. This doesn't seem
to be the cause now though. It does, however, seem to be connected with high
resource use, such as when BE is running or RDP is transferring a file, but
why the latter would cause such a drain I don't know.

Charles
 
Hi Cor

I haven't tried that one before, and I see it says "Timers are not
guaranteed to execute exactly when the time interval occurs, but they are
guaranteed to not execute before the time interval occurs", so perhaps it
could behave the same as the one I've got, but still worth a try.

Cheers

Charles
 
The signalling system should not be re-entrant. If the process that runs at
each tick doesn't complete in time then there's no point in trying to start
another one. If and when, however, the process times out, then a new process
should be started 10 seconds from when the last one started, or as near as.

I keep referring to this as a process, but it's really just a heartbeat. A
message is sent to a remote system every 10 seconds, and a reply is
returned. If the remote system doesn't hear a heartbeat for 20 seconds it
shuts down. If this happens it has to be restarted manually, so I don't want
it to keep shutting down.

So that is why I say that +/- 5 seconds is acceptable. I have a timeout on
receiving a reply of 8 seconds. That way, if I don't get a timely reply
there is a wait of 2 seconds before I send the next heartbeat.

Charles
 
Charles said:
I keep referring to this as a process, but it's really just a
heartbeat. A message is sent to a remote system every 10 seconds, and
a reply is returned. If the remote system doesn't hear a heartbeat
for 20 seconds it shuts down. If this happens it has to be restarted
manually, so I don't want it to keep shutting down.

So that is why I say that +/- 5 seconds is acceptable. I have a
timeout on receiving a reply of 8 seconds. That way, if I don't get a
timely reply there is a wait of 2 seconds before I send the next
heartbeat.

Can't you set the monitor to accept the heartbeat signal at longer
intervals? You already know the monitored system is sometimes too busy to
process it at the currently required frequency, so perhaps the requirement
is wrong.
 
Hi Andrew

Unfortunately, I have no control over the external system. I am just
presented with an interface that I must adhere to. It is a third-party
system, and there is no question that they will change the interface just
for us.

Charles
 
Charles said:
I keep referring to this as a process, but it's really just a heartbeat.
A message is sent to a remote system every 10 seconds, and a reply is
returned. If the remote system doesn't hear a heartbeat for 20 seconds
it shuts down. If this happens it has to be restarted manually, so I
don't want it to keep shutting down.

So that is why I say that +/- 5 seconds is acceptable. I have a timeout
on receiving a reply of 8 seconds. That way, if I don't get a timely
reply there is a wait of 2 seconds before I send the next heartbeat.

Charles

A few questions come to mind:

1. What exactly does the message system look like (sockets, msmq, named
pipe etc. etc.)? Is sending it a blocking operation?

2. Is the reply relevant, and is receival of it a blocking operation?

From what I've gathered, you're sending messages to a remote system, so
the remote system being very busy can't account for the process on your
system timing out, or not raising a timer event on time, unless you're
sending and receiving synchronously and waiting for the remote system to
respond.
 
The messages are well-formed XML over TCP. The send is not a blocking
operation, and indeed messages are exchanged asynchronously, so the reply to
a heartbeat might not be the very next thing the remote system sends; it
might send some unrelated data and send the reply to the heartbeat some
seconds later. The reply is relevant, but only from the point of view of
maintaining integrity. There is no intrinsic value in it. Receiving the
reply does not block either, and if no reply appears after 8 seconds then my
app gives up.

What can happen is that the reply is delayed and appears after the next
heartbeat has been sent. In this situation, my app discards 'out of date'
replies and keeps waiting (up to 8 seconds) for the genuine reply.

Charles
 
Back
Top