Thread: Terrible lag in WaitForMultipleObjects

  1. #1
    Registered User
    Join Date
    May 2004
    Posts
    73

    Terrible lag in WaitForMultipleObjects

    Hey everyone, I've been using WaitForMultipleObjects in my server, and I find that its fourth argument, the timeout in milliseconds, is *terribly* inaccurate. In 100 tries, of waits of .4 to 3.0 seconds, it's on average late returning by 1.154189 seconds (results at WFMO Timeout Accuracy - Pastebin.com and testing code at WFMO Timeout Tester - Pastebin.com).

    Is this normal? Perhaps WFMO really only has down-to-the-second accuracy?

    In any case, is there any way I can mimic WFMO with a better timer?

  2. #2
    the hat of redundancy hat nvoigt's Avatar
    Join Date
    Aug 2001
    Location
    Hannover, Germany
    Posts
    3,130
    You seem to mix microseconds and ticks. Look up QueryPerformanceFrequency, you cannot make comparisons from ticks to time units without this value.
    hth
    -nv

    She was so Blonde, she spent 20 minutes looking at the orange juice can because it said "Concentrate."

    When in doubt, read the FAQ.
    Then ask a smart question.

  3. #3
    'Allo, 'Allo, Allo
    Join Date
    Apr 2008
    Posts
    639
    Code:
    #include <iostream>
    using namespace std;
    #include <windows.h>
    #include <cstdlib>
    
    #pragma comment(lib, "winmm.lib")
    
    DWORD getSystemTimeMilliseconds() {
        return timeGetTime();
    }
    
    int test() {
        HANDLE hEvent = CreateEvent(NULL, FALSE, FALSE, NULL);
    
        const int numTrials = 100;
        srand(GetTickCount());
    
        DWORD millisecondsLateSum = 0;
        DWORD bytes = 0;
    
        for (int i = 0; i < numTrials; i++) {
            DWORD timeBeforeWaitMilliseconds = getSystemTimeMilliseconds();
            DWORD desiredWaitMilliseconds = rand();
            DWORD desiredTimeAfterWaitMilliseconds = timeBeforeWaitMilliseconds + desiredWaitMilliseconds;
            WaitForMultipleObjects(1, &hEvent, FALSE, desiredWaitMilliseconds);
            DWORD timeAfterWaitMilliseconds = getSystemTimeMilliseconds();
    
            DWORD millisecondsLate = timeAfterWaitMilliseconds - desiredTimeAfterWaitMilliseconds;
    
            std::cout << "from " << timeBeforeWaitMilliseconds << " desired wait of " << desiredWaitMilliseconds << " to desired end time of " << desiredTimeAfterWaitMilliseconds << " actually ended " << timeAfterWaitMilliseconds << " late by " << millisecondsLate << " milliseconds" << std::endl;
            millisecondsLateSum += millisecondsLate;
        }
        CloseHandle(hEvent);
    
        std::cout << "late by on average " << millisecondsLateSum / numTrials << " milliseconds" << std::endl;
    
        return 0;
    }
    Results are here, bottom line:
    late by on average 0 milliseconds.

  4. #4
    Registered User VirtualAce's Avatar
    Join Date
    Aug 2001
    Posts
    9,607
    Also the default period for timeGetTime() is usually 5ms which is not ideal. You should use timeBeginPeriod() and timeEndPeriod() to set the desired period. AFAIK it can have a resolution of 1 ms but I would not count on getting that every time. Also this information was true for Windows NT / 2000 / XP but I cannot find any info as to whether it applies in Vista and Windows 7. In Windows 95 the default resolution of timeGetTime() was 1 ms.

  5. #5
    'Allo, 'Allo, Allo
    Join Date
    Apr 2008
    Posts
    639
    Yeah, you can print the current resolution and the allowable ranges with this
    Code:
    // a rare sighting of the mythical timeGetPeriod
    void PrintCurrentTimerResolutions()
    {
        // reutrn should be NTSTATUS but the typedef isn't in windows.h or ntstatus.h (go figure)
        // adding winternl.h or ntsecapi.h solely for it is overkill
        typedef long (NTAPI*pfnNtQueryTimerResolution)(PULONG pMaxRes, PULONG pMinRes, PULONG pCurRes);
        HMODULE hNtDll = GetModuleHandleW(L"ntdll.dll");
        pfnNtQueryTimerResolution ntQueryTimerResolution = 
            (pfnNtQueryTimerResolution)GetProcAddress(hNtDll, "NtQueryTimerResolution");
        // 100-nanosecond units in 1 MS
        static const ULONG REFTIMES_PER_MILLISEC = 10000;
        if(ntQueryTimerResolution)
        {
            ULONG curRes = 0, minRes = 0, maxRes = 0;
            ntQueryTimerResolution(&maxRes, &minRes, &curRes);
            printf(
                "Max res: %lu, ms: %lu\nMin res: %lu, ms: %lu\nCur res: %lu, ms: %lu\n",
                maxRes, maxRes / REFTIMES_PER_MILLISEC,
                minRes, minRes / REFTIMES_PER_MILLISEC,
                curRes, curRes / REFTIMES_PER_MILLISEC
            );
        }
    }
    The test above was done with results of
    Max res: 156001, ms: 15
    Min res: 5000, ms: 0
    Cur res: 10000, ms: 1

    I reran it on a 7x64 VM with timer results of
    Max res: 156250, ms: 15
    Min res: 5000, ms: 0
    Cur res: 156250, ms: 15
    and the bottom line was "late by on average 16 milliseconds". The takeaway is 'as late as the clock' which is logical. The other would seem to be you can set the period to <1ms but not via any Microsoft documented functions.
    Last edited by adeyblue; 12-27-2011 at 10:04 PM.

  6. #6
    Registered User
    Join Date
    May 2004
    Posts
    73
    Awesome, you guys were right! I was mixing microseconds and ticks. Once I put in that frequency call, it started working, being off on average by 100 microseconds or less.

    Something odd did happen though, WFMO was sometimes returning 100 microseconds *before* it should have, but I suppose that should be expected with millisecond precision waiting.

Popular pages Recent additions subscribe to a feed

Similar Threads

  1. WaitForMultipleObjects and listen()/accept()
    By Verdagon in forum Windows Programming
    Replies: 4
    Last Post: 12-19-2011, 10:22 PM
  2. WaitForMultipleObjects for Boost.Thread?
    By Elysia in forum C++ Programming
    Replies: 8
    Last Post: 05-23-2009, 12:18 PM
  3. Can somebody help me...!!!! This is terrible!!!
    By AssistMe in forum C Programming
    Replies: 6
    Last Post: 02-21-2005, 03:30 AM
  4. My teeth are terrible
    By Displeased in forum A Brief History of Cprogramming.com
    Replies: 8
    Last Post: 03-17-2003, 09:38 AM
  5. Terrible Counting prog
    By Unregistered in forum C++ Programming
    Replies: 2
    Last Post: 03-04-2002, 07:48 PM