Thread: win32 - timeSetEvent(): what is wrong with these function?

  1. #1
    Registered User
    Join Date
    Aug 2013
    Posts
    451

    win32 - timeSetEvent(): what is wrong with these function?

    timeSetEvent() - https://msdn.microsoft.com/en-us/lib...=vs.85%29.aspx

    the TIME_PERIODIC is for a time cycle and the TIME_ONESHOT is for it just once, right?

    if so why i'm getting unexpected results?
    Code:
    void Stop()
        {
            if(timerid!=NULL)
            {
                timeKillEvent(timerid);
                //timeEndPeriod (m_uResolution);
                timerid=0;
            }
        }
    
    void Start(bool periodic=true)
        {
            blnPeriodic=periodic;
            Stop();
            /*TIMECAPS tc;
            timeGetDevCaps(&tc, sizeof(TIMECAPS));
            m_uResolution = tc.wPeriodMin;
            timeBeginPeriod(m_uResolution);*/
            UINT timeoptions=0;
    
            if(blnPeriodic==true)
                timeoptions=TIME_PERIODIC;
            else
                timeoptions=TIME_ONESHOT;
    
            timerid = timeSetEvent(intInterval, intInterval/2, &Timer::_TimerProc, (DWORD_PTR)this,timeoptions);
        }
    Code:
    if(blnPeriodic==true)
                timeoptions=TIME_PERIODIC;
            else
                timeoptions=TIME_ONESHOT;
    please correct me these. i'm getting problems with it without understand what is wrong
    1 timer,TIME_PERIODIC, is just do it once
    Last edited by joaquim; 04-24-2016 at 12:27 PM.

  2. #2
    Registered User
    Join Date
    Apr 2013
    Posts
    1,658
    Just a guess here, but try setting resolution to a smaller number. You could try zero to see if that helps, then try larger values. Without a call to timeBeginPeriod(), I'm wondering if the timer just runs at the default tick rate, which is 15.625 ms (64hz), despite the resolution parameter passed to timeSetEvent(). Some really old example C code to check if 1ms timer is really 1ms (it's not on Windows XP, which runs at 1024hz with occasional double ticks to average 1000hz, it is 1ms on Windows 7 and later, and I don't know about Windows Vista).

    Code:
    #include <windows.h>
    #include <stdio.h>
    
    
    #pragma comment(lib, "winmm.lib")       /* include winmm.lib */
    
    
    /*----------------------------------------------------------------------*/
    /*      data                                                            */
    /*----------------------------------------------------------------------*/
    static TIMECAPS sTimeCaps;              /* min and max timer values */
    static MMRESULT mmrTimerId;             /* timer id */
    static volatile DWORD dwTicks = (0-1);  /* tick counter */
    
    
    static LARGE_INTEGER liPerfFrequency;   /* 64 bit frequency */
    static LARGE_INTEGER liDecFrequency;    /* decimal frequency */
    
    
    static volatile LARGE_INTEGER aliPerfCount[1032];  /* 64 bit query counts */
    
    
    static double dDeltams;                 /* elapsed time in ms */
    
    
    /*----------------------------------------------------------------------*/
    /*      code                                                            */
    /*----------------------------------------------------------------------*/
    void CALLBACK TimerFunction(UINT, UINT, DWORD, DWORD, DWORD);
    
    
    /*----------------------------------------------------------------------*/
    /*      main                                                            */
    /*----------------------------------------------------------------------*/
    int main(int argc, char **argv)
    {
    int i;
    
    
    /*                                      ** get min and max period */
        timeGetDevCaps(&sTimeCaps, sizeof(sTimeCaps));
        if(sTimeCaps.wPeriodMin != 1){
            printf("1 ms resolution not allowed\n");
            goto exit1;}
    
    
        QueryPerformanceFrequency(&liPerfFrequency);
    
    
        timeBeginPeriod(1);                 /* set period to 1ms */
        Sleep(128);                         /* wait for it to stabilize */
    
    
    /*                                      ** create 1ms timer to set event */
        mmrTimerId = timeSetEvent(1, 0, TimerFunction, 0, TIME_PERIODIC);
        if(mmrTimerId == (MMRESULT)0){
            printf("Failed to generate multimedia timer.\n");
            goto exit0;}
    
    
        Sleep(2048);                        /* wait for counts to get stored */
    
    
        timeKillEvent(mmrTimerId);          /* stop the timer */
    
    
        for(i = 0; i < 1024; i++){
            dDeltams = (double)(aliPerfCount[i+1].QuadPart - aliPerfCount[i].QuadPart) * 1000. /
                       (double)(liPerfFrequency.QuadPart);
            printf("%8.4lf", dDeltams);
            if((i&7) == 7)
                printf("\n");
        }
    
    
        dDeltams = (double)(aliPerfCount[1024].QuadPart - aliPerfCount[0].QuadPart) * 1000. /
                   (double)(liPerfFrequency.QuadPart);
        printf("%16.4lf\n", dDeltams);
    
    
    exit0:
        timeEndPeriod(1);                   /* restore resolution to default */
    
    
    exit1:
        return(0);
    }
    
    
    /*----------------------------------------------------------------------*/
    /*      TimerFunction       increments dwTicks                          */
    /*----------------------------------------------------------------------*/
    void CALLBACK TimerFunction(UINT uTimerID, UINT uMsg,
                            DWORD dwUser, DWORD dw1, DWORD dw2)
    {
        dwTicks += 1;                           /* increment ticks */
        if(dwTicks < 1032)                      /* store count */
            QueryPerformanceCounter((PLARGE_INTEGER)&aliPerfCount[dwTicks]);
    }
    Last edited by rcgldr; 04-24-2016 at 06:52 PM.

  3. #3
    Registered User
    Join Date
    Aug 2013
    Posts
    451
    rcgldr: i'm sorry, but lets go back:
    Code:
    void Start(bool periodic=true)
        {
             if(periodic==false)
                timerid = timeSetEvent(intInterval, 0, Timer::_TimerProc, (DWORD)this,TIME_ONESHOT);
            else
                timerid = timeSetEvent(intInterval, 0, Timer::_TimerProc, (DWORD)this,TIME_PERIODIC);
        }
    why these if is 'confused'?
    i CAN'T control these if
    realy. is the Compiler!?! i don't know. but i only see here. if i could control between TIME_ONESHOT and TIME_PERIODIC(between Timer objects\instances), i can fix my problem. but i can't control it

  4. #4
    Registered User
    Join Date
    Apr 2013
    Posts
    1,658
    I'm not sure what you're asking now. Have you tried stepping through the code with a source level debugger (like Visual Studio Express, which is free)?

  5. #5
    Registered User
    Join Date
    Aug 2013
    Posts
    451
    seems that i must give up on timeSetEvent() for avoid several problems. but i need precison accuraty. and less than 100ms

  6. #6
    Registered User
    Join Date
    Apr 2013
    Posts
    1,658
    Many games with fixed frequency loops use something like this. It avoids long term drift by using a one time reference to an original time count. This is Windows XP compatible where a Sleep(1) could take up to just under 2ms.

    Code:
    /* code for a thread to run at fixed frequency */
    typedef unsigned long long UI64;        /* unsigned 64 bit int */
    #define FREQ    400                     /* frequency */
    DWORD    dwLateStep;                    /* late step count (for debug) */
    LARGE_INTEGER liPerfFreq;               /* 64 bit frequency */
    LARGE_INTEGER liPerfTemp;               /* used for query */
    UI64 uFreq = FREQ;                      /* thread frequency */
    UI64 uOrig;                             /* original tick */
    UI64 uWait;                             /* tick rate / freq */
    UI64 uRem = 0;                          /* tick rate % freq */
    UI64 uPrev;                             /* previous tick based on original tick */
    UI64 uDelta;                            /* current tick - previous */
    UI64 u2ms;                              /* 2ms of ticks */
    UI64 i;
    
        /* ... */ /* wait for some event to start thread */
        QueryPerformanceFrequency(&liPerfFreq);
        u2ms = ((UI64)(liPerfFreq.QuadPart)+499) / ((UI64)500);
    
        timeBeginPeriod(1);                 /* set period to 1ms */
        Sleep(128);                         /* wait for it to stabilize */
    
        QueryPerformanceCounter((PLARGE_INTEGER)&liPerfTemp);
        uOrig = uPrev = liPerfTemp.QuadPart;
    
        while(1){
            /* update uWait and uRem based on uRem */
            uWait = ((UI64)(liPerfFreq.QuadPart) + uRem) / uFreq;
            uRem  = ((UI64)(liPerfFreq.QuadPart) + uRem) % uFreq;
            /* wait for uWait ticks */
            while(1){
                QueryPerformanceCounter((PLARGE_INTEGER)&liPerfTemp);
                uDelta = (UI64)(liPerfTemp.QuadPart - uPrev);
                if(uDelta >= uWait)
                    break;
                if((uWait - uDelta) > u2ms)
                    Sleep(1);
            }
            if(uDelta >= (uWait*2))
                dwLateStep += 1;
            uPrev += uWait;
            /* fixed frequency code goes here */
            /*  along with some type of break when done */
        }
    
        timeEndPeriod(1);                   /* restore period */
    Last edited by rcgldr; 04-25-2016 at 02:21 PM.

  7. #7
    Registered User Codeplug's Avatar
    Join Date
    Mar 2003
    Posts
    4,981
    Found some interesting information I thought I'd share: Timing in Win32

    gg

  8. #8
    Registered User
    Join Date
    Apr 2013
    Posts
    1,658
    Quote Originally Posted by Codeplug View Post
    Found some interesting information I thought I'd share: Timing in Win32
    The final code sample is similar to the example fixed frequency code in post #6. The code in post #6 handles frequencies that aren't a multiple of 1 khz, (uRem handles the remainder to keep frequency within a counter period of the desired frequency), and also prevents drift, since the previous count is based off an original reading and updated by the desired wait time, as opposed to re-reading the current counter.

    The OS affects the timer inteface. After a beginTimePeriod(1), Win XP runs the timer at 1024 hz, adding a double tick at the 43rd, 86th, and 128th ticks, noting that 128 ticks == 125 ms, which is is how it approximates a 1 khz ticker. This means that occasionally Sleep(1) will occasionally wait 2/1024hz (1.953125 ms), 3 times every 1/8th of a second. Win 7 (and later) run at 1 khz. I don't know about Win Vista. On my system (multi-boot), Win XP query performance frequency is about 3.4 ghz, the cpu clock rate, while Win 7 frequency is around 3.3 mhz (probably a different timer).

  9. #9
    Registered User
    Join Date
    Aug 2013
    Posts
    451
    i'm sorry. i was trying testing the timerid, on filename that don't works, and i get NULL. so i used the GetLastError().
    i have get:
    5 - Access is denied.
    i'm sorry, but don't make sence to me. can you explain better?

  10. #10
    Registered User
    Join Date
    Apr 2013
    Posts
    1,658
    Quote Originally Posted by joaquim View Post
    i'm sorry. i was trying testing the timerid, on filename that don't works, and i get NULL. so i used the GetLastError().
    i have get:
    5 - Access is denied.
    i'm sorry, but don't make sense to me. can you explain better?
    What filename? There's no filename involved with timeSetEvent(). If your code is doing something with a file and getting access denied, it's related to the file related functions, not the timer related functions.

  11. #11
    Registered User
    Join Date
    Aug 2013
    Posts
    451
    my Timer class(with timeSetEvent()) is used with GDIPLUS::Image for animation(like animated gif's).
    but the timerid(timeSetEvent() result) can give me NULL. so I used the GetLastError() for get the error
    Last edited by joaquim; 04-28-2016 at 10:23 AM.

  12. #12
    Registered User
    Join Date
    Apr 2013
    Posts
    1,658
    Can you try the example in post #2? Build it as a windows console application, and run it from a dos console window. Did you use the pragma to include winmm.lib?

  13. #13
    Registered User
    Join Date
    Aug 2013
    Posts
    451
    i use Code Blocks. so i can't use pragma, i use compiler options for add lib files.
    anotherthing(maybe counts): i'm using, on same time but on diferent intervals, 7 instances of my Timer class. do you need my entire class?

  14. #14
    Registered User
    Join Date
    Apr 2013
    Posts
    1,658
    Quote Originally Posted by joaquim View Post
    i use Code Blocks. so i can't use pragma, i use compiler options for add lib files.
    anotherthing(maybe counts): i'm using, on same time but on diferent intervals, 7 instances of my Timer class. do you need my entire class?
    Do all of the calls to timeSetEvent() fail or do only some of them fail?

    The alternative is to use query performance counter with sleep() to avoid tying up a cpu core. If this is in the 10ms to 100ms range, then most of the time will be spent in the sleep call as opposed to polling the performance counter.
    Last edited by rcgldr; 04-28-2016 at 05:53 PM.

  15. #15
    Registered User
    Join Date
    Aug 2013
    Posts
    451
    printed:
    Code:
    error    0
    error    5
    error    5
    error    5
    Code:
    void Start()
        {
            Stop();
            TIMECAPS tc;
            timeGetDevCaps(&tc, sizeof(TIMECAPS));
            m_uResolution = min(max(tc.wPeriodMin, 0), tc.wPeriodMax);
            timeBeginPeriod(m_uResolution);
            timerid = timeSetEvent(intInterval, m_uResolution, Timer::_TimerProc, (DWORD)this,TIME_PERIODIC | TIME_KILL_SYNCHRONOUS);
    
            if (timerid==NULL)
                DebugText("error\t" + to_string(GetLastError()));//checking the result for print
        }
    
    static void CALLBACK _TimerProc(UINT wTimerID, UINT msg, DWORD dwUser, DWORD dw1, DWORD dw2)
        {
            Timer* obj=(Timer*)dwUser;
            if(obj!=nullptr && obj->timerprocedure!=nullptr)
            {
                obj->calltimerfunction();
            }
        }

Popular pages Recent additions subscribe to a feed

Similar Threads

  1. timeSetEvent
    By Mole42 in forum Windows Programming
    Replies: 3
    Last Post: 09-15-2010, 10:55 AM
  2. win32 timer function
    By Anuradh_a in forum Windows Programming
    Replies: 2
    Last Post: 03-04-2008, 11:51 AM
  3. timeSetEvent problem
    By likeregularchic in forum Windows Programming
    Replies: 6
    Last Post: 09-10-2005, 07:36 PM
  4. What's wrong with my Win32 Wrapper code?
    By miica in forum Windows Programming
    Replies: 9
    Last Post: 02-22-2005, 08:55 PM
  5. compiling mingw to enable timeSetEvent
    By underthesun in forum Windows Programming
    Replies: 2
    Last Post: 02-02-2005, 06:00 PM