1

I was testing how long a various win32 API calls will wait for when asked to wait for 1ms. I tried:

::Sleep(1)
::WaitForSingleObject(handle, 1)
::GetQueuedCompletionStatus(handle, &bytes, &key, &overlapped, 1)

I was detecting the elapsed time using QueryPerformanceCounter and QueryPerformanceFrequency. The elapsed time was about 15ms most of the time, which is expected and documented all over the Internet. However for short period of time the waits were taking about 2ms!!! It happen consistently for few minutes but now it is back to 15ms. I did not use timeBeginPeriod() and timeEndPeriod calls! Then I tried the same app on another machine and waits are constantly taking about 2ms! Both machines have Windows XP SP2 and hardware should be identical. Is there something that explains why wait times vary by so much? TIA

user316606
  • 231
  • 1
  • 3
  • 7
  • 4
    Why do you *care* if the time varies that much? If you need millisecond-precision timing, use an RTOS instead of Windows. http://en.wikipedia.org/wiki/RTOS – Matti Virkkunen Apr 14 '10 at 14:38
  • almost certainly another application has used timeBeginPeriod to modify the interrupt period. I bet the "about 2ms" were 2 x 0.9765625 ms= 1.9593125 ms! See [this](http://stackoverflow.com/questions/85122/sleep-less-than-one-millisecond/11456112#11456112). – Arno Aug 01 '12 at 08:16
  • or [this](http://stackoverflow.com/questions/5801813/c-usleep-is-obsolete-workarounds-for-windows-mingw/11470617#11470617) – Arno Aug 01 '12 at 08:27

5 Answers5

4

Thread.Sleep(0) will let any threads of the same priority execute. Thread.Sleep(1) will let any threads of the same or lower priority execute.

Each thread is given an interval of time to execute in, before the scheduler lets another thread execute. As Billy ONeal states, calling Thread.Sleep will give up the rest of this interval to other threads (subject to the priority considerations above).

Windows balances over threads over the entire OS - not just in your process. This means that other threads on the OS can also cause your thread to be pre-empted (ie interrupted and the rest of the time interval given to another thread).

There is an article that might be of interest on the topic of Thread.Sleep(x) at:

Priority-induced starvation: Why Sleep(1) is better than Sleep(0) and the Windows balance set manager

Thomas Bratt
  • 40,822
  • 34
  • 113
  • 133
3

Changing the timer's resolution can be done by any process on the system, and the effect is seen globally. See this article on how the Hotspot Java compiler deals with times on windows, specifically:

Note that any application can change the timer interrupt and that it affects the whole system. Windows only allows the period to be shortened, thus ensuring that the shortest requested period by all applications is the one that is used. If a process doesn't reset the period then Windows takes care of it when the process terminates. The reason why the VM doesn't just arbitrarily change the interrupt rate when it starts - it could do this - is that there is a potential performance impact to everything on the system due to the 10x increase in interrupts. However other applications do change it, typically multi-media viewers/players.

Bill the Lizard
  • 369,957
  • 201
  • 546
  • 842
Michael Burr
  • 311,791
  • 49
  • 497
  • 724
1

The biggest thing sleep(1) does is give up the rest of your thread's quantum . That depends entirely upon how much of your thread's quantum remains when you call sleep.

Billy ONeal
  • 97,781
  • 45
  • 291
  • 525
  • This is not quite right when there is no other thread. I need to pull your attention to [this thread](http://stackoverflow.com/questions/3361059/how-to-get-an-accurate-1ms-timer-tick-under-winxp/11453259#11453259). – Arno Aug 01 '12 at 08:20
  • @Arno: It's entirely right. If there are no other threads, then of course giving up your quantum doesn't do anything, because you get immedately scheduled for a new quantum. That doesn't change that calling sleep did give up the quantum in the first place. – Billy ONeal Aug 01 '12 at 17:57
  • Well, I agree. Saying it that way means that any sleep() ends the threads quantum, no matter what `dwMillisonds` is supplied. – Arno Aug 02 '12 at 10:23
1

To aggregate what was said before:

CPU time is assigned in quantums (time slices)
The thread scheduler picks the thread to run. This thread may run for the entire time slice, even if threads of higher priority become ready to run.

Typical time slices are 8..15ms, depending on architecture.

The thread can "give up" the time slice - typically Sleep(0) or Sleep(1). Sleep(0) allows another thread of same or hogher priority to run for the next time slice. Sleep(1) allows "any" thread.

The time slice is global and can be affected by all processes
Even if you don't change the time slice, someone else could.

Even if the time slice doesn't change, you may "jump" between the two different times.

For simplicity, assume a single core, your thread and another thread X.

If Thread X runs at the same priority as yours, crunching numbers, Your Sleep(1) will take an entire time slice, 15ms being typical on client systems.

If Thread X runs at a lower priority, and gives up its own time slice after 4 ms, your Sleep(1) will take 4 ms.

peterchen
  • 38,919
  • 19
  • 95
  • 176
0

I would say it just depends on how loaded the cpu is, if there arent many other process/threads it could get back to the calling thread a lot faster.

Francisco Noriega
  • 11,255
  • 10
  • 47
  • 70