Virtual Developer Workshop: Containerized Development with Docker

Environment: Timers, miscellaneous


This class supplies an accurate timer (figured in milliseconds). There are two advantages to this class instead of the normal Sleep():

  • It can sleep the remaining time of a chosen period, causing exact timeframes
  • It's more accurate

The need for this class lies in the fact that I needed to do an action exactly every second. In my case, it is used to communicate with a PLC, and the action has some I/O every second. This can take a considerable amount of time. But, you can use it for any purpose.

When you want something to execute every second, and your action takes 300 ms, you face the problem that with a Sleep(1000) after the action, the complete process takes more then 1300 milliseconds.

A further problem was the accuracy of a Sleep. This is not high. A Sleep of 300ms can take 310ms. a Sleep of 1ms takes at least 8ms. I did a check on different machines; it is always different and always bad.

To avoid this inaccuracy of Sleep, I only used Sleep() to approach the end time up to 15 milliseconds. In the last part, I used a dirty for() loop. Because this loop generates a big CPU usage, I only used this at the very end of the waiting time. Because of the small period, you cannot see any difference in the NT-performance meter.

When you don't need to use this level of accuracy, only the remain sleep function, InitTimer(false), will avoid this for() loop, to the disadvantage of the accuracy.

And How Does It Work Under Water?

The best way for a good timer to operate is to use the QueryPerformanceCounter(). It gives clockpulses. Because this is hardware-dependent, we need to know the frequency (how many pulses per second). This is achieved by using QueryPerformanceFrequency(). QueryPerformanceCounter() works with a struct LARGE_INTEGER, which has some disadvantages when calculating. It's no problem to use a LONGLONG (__int64) and cast it. This saves us from a lot of casting and time-consuming member accesses.

Because my app runs for long times, I looked to the maximum time it could run: We store in a __int64; its maximum val is 9.22337E+18 (=2^63). This is the maximum period we can sleep.

The frequency/divider of a P2-333 MHz is 1,193,180
The frequency/divider of a P4-2.4 GHz is 3,579,545

The worse case is P4. This means we can store a maximum of:

2,576,688,388,288 seconds
   42,944,806,471 minutes
      715,746,775 hours
       29,822,782 days
           81,706 years

This is enough for my humble program...

Internal variables are all saved as clockpulses, not in milliseconds. All user input/output is done in milliseconds and translated to/from clockpulses.

The function SleepNow() acts just as an ordinary Sleep() but when you name it the same, there is an unwanted case of recursive programming when you just need ten original Sleep() cycles.

When sleeping, it acts the same as a normal sleep: You cannot interact with the app anymore. You can put it in a separate thread to avoid this. In the test app, I didn't do this. It's just a simple test container about the use of the timer class. In your own app, it's enough to include CKETimer.cpp and CKETimer.h.

To Do

Yes, I left some ends open, so you guys (girls?) out there can extend it with your ideas:

  • I don't like the for loop, but I can't think of a process that is short (<1ms) and doesn't boos CPU usage.
  • Make it thread safe
  • Test it on other OS/PC's (it works on Win98, 2000 and XP, all >= P2)


Download source - 24 Kb


  • It's not SLEEP

    Posted by hover on 10/15/2007 03:52am

    Hi! The for loop can not simulate the sleep(). For sleep(), the sleeping thread will give its cpu time to other threads anyway, while for loop thread will still consume cpu time until the system takes this thread's cpu time due to cpu time scheduling.

  • Use OnTimer event from CWnd

    Posted by Legacy on 04/23/2003 07:00am

    Originally posted by: Francois Cantin

    Have you considered using the OnTimer event from CWnd?
    I don't know if it is accurate enough for your purpose but it is very easy to use.

  • Multimedia Timers

    Posted by Legacy on 04/17/2003 07:00am

    Originally posted by: John Peloquin

    Multimedia timers can also be used to provide accurate timing. Specifically, they can provide resolution of up to 1 millisecond. See the MSDN Library for information.

  • Good Work

    Posted by Legacy on 04/16/2003 07:00am

    Originally posted by: Michael Williamson

    > The only thing I could suggest is a bit better
    > description of what the functions do. You only call
    > TimerRollOver() from your CKETimer class, and I don't
    > know why I should call it, so it should be a private
    > or protected member.

    You are right, but TimerRollOver was only for
    debugging purposes: When the timer reaches _int64 maximum, it rolls over to 0 again. this func gives you a notice
    (after 82000 years)
    I could have ripped it out.

    > You call and store the result of CheckFreq(), but I can't
    > figure out what it is for. You can never used the stored > result.

    The CKETimer class was the thing I wanted to submit.
    The Dlg was only meant as a test container, and I used it
    for checking the functionality on other PC's and give a
    quick view to the use.

    > This (TimerTestDlg.cpp line 139)
    > m_bAccurate?TRUE:FALSE
    > is faster as simply
    > m_bAccurate == TRUE

    That was a small error: The correct way is:
    if (!aTimer.InitTimer(m_bAccurate?true:false))

    The MFC wizard binds a BOOL to a checkbox, and I prefer
    the use of bool, because it has less memory use and you
    are warned when you try to put non-bool values in it.
    But when you just mix them, you get a performance warning
    when compiling.
    This inline if doesn't set m_bAccurate to TRUE, but
    when m_bAccurate=TRUE, then the result is true, otherwise
    it's false

  • You must have javascript enabled in order to post comments.

Leave a Comment
  • Your email address will not be published. All fields are required.

Most Popular Programming Stories

More for Developers

RSS Feeds

Thanks for your registration, follow us on our social networks to keep up-to-date