Thread: Timing issues in Windows code

  1. #1
    Registered User
    Join Date
    Sep 2017
    Posts
    15

    Question Timing issues in Windows code

    Hi,

    I have written some code that mimics the Grenwich time signal beeps. The programme spends most of the time sleeping. The programme exits sleep just before 5 seconds to the hour, waits for 55 seconds then beeps, then a short sleep waits for 4 seconds to the hour then another beep and so on.

    The code fragment is:

    Code:
            /* Sleep until just before 55 seconds of minute */
            Sleep(millisecondsuntiltoh - 5050);
    
    
            /* Wait until seconds reach 55 */
            while(seconds!=55)
            {
                GetSystemTime(&str_t);
                seconds = str_t.wSecond;
            }
            Beep(1000, shortbeep);
    
    
            /* Sleep until just before 56 seconds of minute */
            Sleep(shortsleep);
            /* Wait until seconds reach 56 */
            while(seconds!=56)
            {
                GetSystemTime(&str_t);
                seconds = str_t.wSecond;
            }
            Beep(1000, shortbeep);
    My problem is that the first beep is noticeably late. Subsequent beeps appear to happen on time. This happens even though the programme has finished the long sleep in time. I know that Windows is not a real-time operating system but what am I doing wrong?

    Any thoughts or ideas appreciated.

    Thank you.

  2. #2
    and the hat of int overfl Salem's Avatar
    Join Date
    Aug 2001
    Location
    The edge of the known universe
    Posts
    38,072
    Why didn't you post the whole thing?
    Your omissions hide a multitude of sins.
    What's millisecondsuntiltoh for example?

    You seem to assume that everything except the sleeps happen in zero time, which is simply not true, and this will contribute to drift.
    If you dance barefoot on the broken glass of undefined behaviour, you've got to expect the occasional cut.
    If at first you don't succeed, try writing your phone number on the exam paper.

  3. #3
    Registered User
    Join Date
    Sep 2017
    Posts
    15
    millisecondsuntiltoh is the number of milliseconds until the top of the hour 0min, 0 seconds of the hour. I am not assuming things happen in zero time and have taken account of this.

  4. #4
    and the hat of int overfl Salem's Avatar
    Join Date
    Aug 2001
    Location
    The edge of the known universe
    Posts
    38,072
    I still can't see your whole code.
    If you dance barefoot on the broken glass of undefined behaviour, you've got to expect the occasional cut.
    If at first you don't succeed, try writing your phone number on the exam paper.

  5. #5
    Registered User
    Join Date
    Sep 2017
    Posts
    15

    Question

    The complete code is:

    Code:
    /* Programme to mimic Grenwich time signal (BBC pips)  Fat Agnus, all rights reserved */
    
    
    #include <Windows.h>
    #include <stdio.h>
    #include <stdlib.h>
    
    
    #define shortsleep 600
    #define shortbeep 100
    #define longbeep 500
    
    
    WORD minutes, seconds, milliseconds, minutesuntiltoh, secondsuntiltom;
    LONG millisecondsuntiltoh, millisecondsuntiltom;
    
    
    void main()
    {
    
     SYSTEMTIME str_t;
    
    /* GetSystemTime(&str_t);
     minutes = str_t.wMinute;
     seconds = str_t.wSecond;
     milliseconds = str_t.wMilliseconds;
     printf("Min:%d\nSecond:%d\nMilliseconds:%d\n"
     ,minutes,seconds,milliseconds);
    */
    
     while(TRUE)
        {
            /* Get system time */
            GetSystemTime(&str_t);
            minutes = str_t.wMinute;
            seconds = str_t.wSecond;
            milliseconds = str_t.wMilliseconds;
    
            /* calculate milliseconds until top of minute */
    /*        millisecondsuntiltom = 60000-(seconds*1000+milliseconds);
            printf("milliseconds until top of minute:%d\n", millisecondsuntiltom); */
            /* calculate milliseconds until top of hour */
    
           /* calculate milliseconds until top of the hour ^/
            millisecondsuntiltoh = 3600000-(minutes*60000+seconds*1000+milliseconds);
    /*        printf("milliseconds until top of hour:%d\n", millisecondsuntiltoh); */
    
            /* Sleep until just before 55 seconds of minute */
            Sleep(millisecondsuntiltoh - 5050);
    /*        printf("Sleep finished\n"); */
    
    
            /* GetSystemTime(&str_t);
            seconds = 54; */
    
    
            /* Wait until seconds reach 55 */
            while(seconds!=55)
            {
                GetSystemTime(&str_t);
                seconds = str_t.wSecond;
            }
            Beep(1000, shortbeep);
    
    
            /* Sleep until just before 56 seconds of minute */
            Sleep(shortsleep);
            /* Wait until seconds reach 56 */
            while(seconds!=56)
            {
                GetSystemTime(&str_t);
                seconds = str_t.wSecond;
            }
            Beep(1000, shortbeep);
    
    
            /* Sleep until just before 57 seconds of minute */
            Sleep(shortsleep);
            /* Wait until seconds reach 57 */
            while(seconds!=57)
            {
                GetSystemTime(&str_t);
                seconds = str_t.wSecond;
            }
            Beep(1000, shortbeep);
    
    
      /* Sleep until just before 58 seconds of minute */
            Sleep(shortsleep);
            /* Wait until seconds reach 58 */
            while(seconds!=58)
            {
                GetSystemTime(&str_t);
                seconds = str_t.wSecond;
            }
            Beep(1000, shortbeep);
    
    
      /* Sleep until just before 59 seconds of minute */
            Sleep(shortsleep);
            /* Wait until seconds reach 59 */
            while(seconds!=59)
            {
                GetSystemTime(&str_t);
                seconds = str_t.wSecond;
            }
            Beep(1000, shortbeep);
    
    
            /* Sleep until just before 0 seconds of minute */
            Sleep(shortsleep);
            /* Wait until seconds reach 0 */
            while(seconds!=0)
            {
                GetSystemTime(&str_t);
                seconds = str_t.wSecond;
            }
            Beep(1000, longbeep);
        }
    }
    The
    Code:
     Sleep(millisecondsuntiltoh - 5050)
    will cause the program to sleep until just before 5 seconds before 55 seconds to the hour. The 5050 figure has been 6000 during development but the problem persists. In fact if I reduce it to very close to 5000 the problem goes away leaving me to think it's a problem to do with a multitasking operating system.

    Thank you.

  6. #6
    and the hat of int overfl Salem's Avatar
    Join Date
    Aug 2001
    Location
    The edge of the known universe
    Posts
    38,072
    You need to understand that Sleep only guarantees a lower bound. That is, at least x. Not exactly x, nor at most x.

    So a sleep of 1 second could take 2 seconds and be perfectly within spec. A long sleep might make the OS lazier about waking your program up, since it's not doing anything particularly time sensitive.

    Also, use a loop instead of copy pasting code.
    for ( t = 55 ; t <= 60 ; t++ )
    If you dance barefoot on the broken glass of undefined behaviour, you've got to expect the occasional cut.
    If at first you don't succeed, try writing your phone number on the exam paper.

  7. #7
    Registered User
    Join Date
    Sep 2017
    Posts
    15
    Thanks Salem. The program wakes from sleep in time as witnessed by my
    Code:
     printf("Sleep finished\n");
    . The 5050 figure has been larger in the past like 6000 but I still have the same problem. I think you are on to something when you talk about the operating system allocating time to my program... The for (t = 5; t <= 60; t++) is better than my quick and dirty copy & pasting code. I was going to sort that out once it was working reliably.

    Can I use another method to use the system clock, like getting a signal from the clock at a certain time? My search couldn't find one.

    Thank you.

  8. #8
    and the hat of int overfl Salem's Avatar
    Join Date
    Aug 2001
    Location
    The edge of the known universe
    Posts
    38,072
    You can get better resolution than 1 second, but you can't solve the underlying problem.
    Wait Functions (Windows)

    You can mess around with process and thread priority as well.
    windows - What is the 'realtime' process priority setting for? - Stack Overflow

    You can improve your average case, but I think there will always be an outlier case where it doesn't work as timely as you would want - especially for any userspace programs.

    Edit:
    Also, main returns int (even though you have while(1) in there), and move all your global variables into main.
    If you dance barefoot on the broken glass of undefined behaviour, you've got to expect the occasional cut.
    If at first you don't succeed, try writing your phone number on the exam paper.

  9. #9
    Registered User
    Join Date
    Sep 2017
    Posts
    15
    Thank you for the tips Salem. I was thinking of changing the priority of the program. As it's sleeping for the majority of the time it should have little impact on system performance.

  10. #10
    Registered User
    Join Date
    Jun 2015
    Posts
    1,643
    Just a cleanup of your code. Since I don't use Windows, I didn't run it (or even compile it).
    Code:
    #include <windows.h>
    
    #define MAIN_SLEEP_DIF  5400
    #define SHORT_SLEEP      600
    #define SHORT_BEEP       100
    #define LONG_BEEP        500
    #define FREQ            1000
    
    int main() {
        SYSTEMTIME tim;
        LONG ms_until_toh;
     
        while (TRUE) {
            GetSystemTime(&tim);
            ms_until_toh = 3600000
                         - (LONG)tim.wMinute * 60000
                         - (LONG)tim.wSecond * 1000
                         - tim.wMilliseconds;
    
            if (ms_until_toh > MAIN_SLEEP_DIF)
                Sleep(ms_until_toh - MAIN_SLEEP_DIF);
    
            for (WORD secs = 55; secs < 60; secs++) {
                do
                    GetSystemTime(&tim);
                while (str_t.wSecond != secs);
                Beep(FREQ, SHORT_BEEP);
                Sleep(SHORT_SLEEP);
            }
    
            do
                GetSystemTime(&tim);
            while (str_t.wSecond != 0);
            Beep(FREQ, LONG_BEEP);
        }
        
        return 0;
    }
    Explode the sunlight here, gentlemen, and you explode the entire universe. - Plan 9 from Outer Space

  11. #11
    Registered User
    Join Date
    Sep 2017
    Posts
    15
    Thank you algorism. I will compile and report back.

  12. #12
    Registered User
    Join Date
    Sep 2017
    Posts
    15
    alogorism I have run your code but still have the same inherent problem. I can change the task priority to real time using Task Manager but that does not seem to make any difference. I assume you don't need to be an administrator for the change in priority to take effect?

  13. #13
    Registered User
    Join Date
    Jun 2015
    Posts
    1,643
    I don't know anything about administrator privileges for windows.

    What does the following code print? If you can get it running, it should show the minimum and maximum available resolutions for timers (in milliseconds).
    Code:
    #include <windows.h>
    #include <stdlib.h>
    #include <stdio.h>
    
    int main() {
        TIMECAPS tc;
    
        if (timeGetDevCaps(&tc, sizeof(TIMECAPS)) != TIMERR_NOERROR) {
            fprintf(stderr, "Can't get timer info\n");
            exit(EXIT_FAILURE);
        }
    
        printf("min: %d  max: %d\n", (int)tc.wPeriodMin, (int)tc.wPeriodMax);
    
        return 0;
    }
    Explode the sunlight here, gentlemen, and you explode the entire universe. - Plan 9 from Outer Space

  14. #14
    Registered User
    Join Date
    Sep 2017
    Posts
    15
    I can't get that code to compile as is, the compiler doesn't like timeGetDevCaps. I can look at this in the evening.
    Last edited by Fat Agnus; 09-04-2017 at 12:25 AM.

  15. #15
    Registered User
    Join Date
    Apr 2013
    Posts
    1,656
    You didn't mention which version of Windows you're using. Beep() uses the speaker on Windows XP, doesn't work at all on Windows Vista, and uses the sound card on Windows 7 or later. Multiple beep calls in Windows XP work, but in Windows 7, there's a short bit of silence between beeps. On Windows XP, the clock used for sleep runs at 1024hz, with 1000hz simulated by adding an extra ticker delay 3 time each 128 ticks to end up at 125 ms. Windows 7 runs that clock at 1000hz.

    The ticker for both Window XP and Windows 7 runs at 64 hz, so thread wakeups or context switches occur on a 64 hz boundary. You can increase the ticker rate to 1000hz (1 ms per tick) using timeBeginPeriod(). Don't forget to use timeEndPeriod when done.

    timeBeginPeriod function (Windows)

    I'll try one of the example code above to see what the issue is. There's a data / time chip in addition to the clock and ticker on a PC, and I'm not sure which is used for the time of day type functions.

Popular pages Recent additions subscribe to a feed

Similar Threads

  1. Linux and Windows write timing difference
    By chipbu in forum C Programming
    Replies: 2
    Last Post: 11-20-2012, 02:36 AM
  2. Simple game with timing issues atm
    By Swarvy in forum Game Programming
    Replies: 1
    Last Post: 08-06-2009, 09:52 PM
  3. Timing measurements on windows
    By shani in forum Windows Programming
    Replies: 16
    Last Post: 12-19-2007, 01:59 PM
  4. Timing in Windows
    By steinberg in forum Windows Programming
    Replies: 3
    Last Post: 07-14-2002, 12:43 AM
  5. timing issues
    By jibblit in forum C Programming
    Replies: 6
    Last Post: 03-25-2002, 10:26 AM

Tags for this Thread