4 ms·
I don't even get why you would Sleep() in such a scenario. If you want to fire every 1ms, wouldn't you use an actual timer? Like one of SetTimer/SetThreadpoolTi
by mehrdadn 6y ago
I don't even get why you would Sleep() in such a scenario. If you want to fire every 1ms, wouldn't you use an actual timer? Like one of SetTimer/SetThreadpoolTimer/CreateTimerQueueTimer/timeSetEvent/CreateWaitableTimer maybe? Why would you rely on Sleep() for periodicity?
- gambiting 6y agoLiterally all of those methods will only wake up at the system's timer interval at the earliest - if that happens to be 16ms, there is nothing you can do to sleep/wait less than 16ms. Even WaitForObject calls can only wait for the minimum equal to the system's timer resolution.
- mehrdadn 6y agoThe resolution or behavior of other APIs is beside my point. I'm saying, even if in an ideal world Sleep did wait exactly how much you told it to, I don't get why you would feel justified in using it to trigger something every N ms. Even if N = 16ms. Your code itself might takes 3ms to run one time, 6ms another time, or 9ms a third time. Sleeping 16ms every time just won't get you periodic behavior even if Sleep is perfectly accurate. Right? i.e. Sleep() just seems like the wrong API regardless of everything else...
- deleted 6y ago[deleted]
- gambiting 6y agoI don't think I understand your concern here. The idea wasn't to do something every N millis, the loop was "process work, if there isn't any more work to do, sleep(1), repeat". Like you said, the "work" part can take any amount of time - but when it does run out, the thread needs to sleep/wait. We have experimented with several APIs for this, including the methods you suggested, and it had no effect on actual time spent waiting for more work to appear - sleep(1) had the exact same effect as simply using WaitForObject and the work producer signalling on that object - the times were literally identical. Edit: reading your comment again I think I see the misunderstanding - sleep wasn't used to do something periodically, if that's what you want to do then indeed, sleep is the wrong tool.
- mehrdadn 6y agoI guess I'm not understanding your use case, if it's not periodic invocation. Why you were calling Sleep(1)? Why was a 16ms sleep problematic in that case?
- vardump 6y agoAgain. Sleep(1) is just a shorthand to discuss about this topic. Exact same behavior affects every other Windows timing mechanism as well.
- gambiting 6y agoBecause once a thread is done with all available work, it has to sleep/wait, the only other alternative is busy waiting(awful idea). So if you see ok, there is no more available work, and call sleep(1), and some more work comes in 2ms later, that work might not be picked up for a whole next 14ms. That is the core of the problem. Like, you are focusing on the sleep(1) part too much - what I want to do is "wait until there is more work available to process, and then wake up and start processing as soon as physically possible". On Windows the "as soon as physically possible" part is unfortunately 16ms in most cases, and that's just not acceptable for something as precise as audio work.
- mehrdadn 6y ago> what I want to do is "wait until there is more work available to process" If this is merely to free up CPU when you have no work to do, then the actual timing of 1ms vs 16ms doesn't seem like the issue, right? Shouldn't you be instead waiting on a condition that gets set when work is queued? Like an event object, or an I/O completion port, or something that indicates work is ready? Instead of polling for the condition? > On Windows the "as soon as physically possible" part is unfortunately 16ms in most cases, and that's just not acceptable for something as precise as audio work. Aren't you contradicting yourself here? If you're doing audio don't you want periodic multimedia timers? Which are built for this purpose and actually also do deliver the resolution you need?
- 6y ago
- vardump 6y agoWhen you're talking about Windows timer accuracy, Sleep is the simplest way to do so. Same issues and resolution affect all of the other mechanisms you mention. Talking about those separately would just introduce unnecessary complexity to the discussion without any advantage. So no one would rely on Sleep for periodicity. Getting reliable timing performance out of Windows is... challenging. So ultimately it's just simpler to talk about Sleep. Windows developers who have to deal with it understand that same mechanism (which used to be determined by the global timer frequency, which you could adjust by calling timeBeginPeriod) affects all of the different timers.
- mehrdadn 6y ago> Same issues and resolution affect all of the other mechanisms you mention. Really? On versions prior to 20H2? This gives me 16ms resolution for SetWaitableTimer but 1ms for timeSetEvent: #include <tchar.h> #include <Windows.h> #include <MMSystem.h> #pragma comment(lib, "winmm.lib") static unsigned int prev_time = timeGetTime(); VOID CALLBACK callback(LPVOID lpArgToCompletionRoutine, DWORD dwTimerLowValue, DWORD dwTimerHighValue) { unsigned int now = timeGetTime(); _tprintf(_T("%u\n"), now - prev_time); prev_time = now; } void CALLBACK callback(UINT uTimerID, UINT uMsg, DWORD_PTR dwUser, DWORD_PTR dw1, DWORD_PTR dw2) { return callback(NULL, 0, 0); } int _tmain(int argc, TCHAR *argv[]) { enum { msec = 1 }; HANDLE handle = CreateWaitableTimer(NULL, FALSE, NULL); LARGE_INTEGER due = {}; SetWaitableTimer(handle, &due, msec, callback, NULL, FALSE); for (int i = 0; SleepEx(100, TRUE) == WAIT_IO_COMPLETION && i < 30; ++i) { } CloseHandle(handle); MMRESULT id = timeSetEvent(msec, 1, callback, NULL, TIME_PERIODIC | TIME_KILL_SYNCHRONOUS); Sleep(100); timeKillEvent(id); }
- gambiting 6y agoI can 100% guarantee that if your system time resolution is 16ms, that timeSetEvent won't actually trigger in 1ms, no matter what it reports.
- mehrdadn 6y agoWell that's not what I'm seeing... can you paste what you get? > clockres && Temp Maximum timer interval: 15.625 ms Minimum timer interval: 0.500 ms Current timer interval: 15.621 ms 0 15 16 ... 16 15 2 1 2 ...
- dspillett 6y ago> I don't even get why you would Sleep() in such a scenario. If you don't want two of the process running at once for any reason, a check-do-sleep loop can be easier to reason than debouncing an interrupt based approach. Less efficient, but often efficient enough especially if you are just throwing something together quickly with a view to if being PoC or a temporary utility.
- beagle3 6y agoSomewhere around 2003 I discovered that the best way to do a short sleep, regardless of timeBeginPeriod() and friends, is to use select() with a short (1ms or 0.5ms) timeout. It worked on Win2K and WinXP, even when Sleep() didn't go below 1ms and wasn't dependable for less than 1ms even with timeBeginPeriod