C# Thread.Sleep malfunction
Messages   Related Types
This message was discovered on microsoft.public.dotnet.framework.
Responses highlighted in red are from those people who are likely to be able to contribute good, authoratitive information to this discussion. They include Microsoft employees, MVP's and others who IMHO contribute well to these kinds of discussions.
Post a new message to this list...

janbak (VIP)
It seems that on some XP platforms the Thread.Sleep method is malfunctioning.
I created a small application that was supposed to show 2 newstickerbars on
the main form, with the added possibility to alter the speed with which they
tick.

To achieve this I use a thread that handles the actual drawing and movement
of the ticker: each tick the target object (in this case a panel) is being
shifted 1 pixel to the left, and the next line is copied onto the right of
the panel (I use a combination of BitBlt and DrawImage to do this).

To control the speed I put the threads to sleep with a delay of around 5
milliseconds, which seems to give a nice effect. However on some systems
(specially XP) when there are 2 tickerbars on the main form, one having a
sleep time of 4 ms and the other having a sleep time of 5 ms, there is NO
visual speed difference: they move at the same speed. On windows2000
professional everything seems to work fine. Does anybody know what is going
wrong here?
(I can give you the sourcecode if needed...)

Reply to this message...
 
    
Bob Milton
You have presumed the time for sleep is exact. In fact, it is only the
minimum time until your thread runs again. Since XP normally runs with
approximately a 10 millisecond scheduler, your 4 and 5 millisecond requests
are almost certainly both 10. Sleep is no good for fine grained timing.
Bob Milton
"janbak" <Click here to reveal e-mail address> wrote in message
news:Click here to reveal e-mail address...
[Original message clipped]

Reply to this message...
 
    
janbak (VIP)
Hmm. So they decided to downgrade the thread accuracy....? very strange since
10 milliseconds is quite a long time. Aren't you confused with normal
WM_TIMER timer. That one has an accuracy of around 10 milliseconds.
Reply to this message...
 
    
Willy Denoyette [MVP] (VIP)
No they didn't, but your thread is not the only runable thread in the system
I guess.
So if you specify a sleep period of 4 msec. that means your thread will
sleep for 4 msec after which he enters the ready state, any running thread
remains running until he is preempted and the scheduler activates another
(not necessarily and most certainly not yours ) thread from the ready queue.
As an example - say you have 10 threads waiting in the queue to be serviced
before your thread, and each thread runs for an average of 2msec. The result
is that your thread effectively "sleeps" 20 msec.

Willy.

"janbak" <Click here to reveal e-mail address> wrote in message
news:Click here to reveal e-mail address...
[Original message clipped]

Reply to this message...
 
    
Per Larsen
On XP, Thread.Sleep's default granularity follows that of the system timer.
To get more accurate results from Thread.Sleep, you must lower the default
timer resolution e.g. to 1 millisecond. There doesn't appear to be a managed
way to do that, but fortunately, importing the relevant WIN32 functionality
is quite simple (outline):

[DllImport("winmm.dll")]
internal static extern uint timeBeginPeriod(uint period);

[DllImport("winmm.dll")]
internal static extern uint timeEndPeriod(uint period);

{

Thread.Sleep(1); // wait's roughtly 15ms on my system
Thread.Sleep(2); // wait's roughtly 15ms on my system
Thread.Sleep(3); // wait's roughtly 15ms on my system

timeBeginPeriod(1);

Thread.Sleep(1); // wait's just over 1 ms on my system
Thread.Sleep(2); // wait's just over 2 ms on my system
Thread.Sleep(3); // wait's just over 3 ms on my system

timeEndPeriod(1);

Thread.Sleep(1); // wait's roughtly 15ms on my system
Thread.Sleep(2); // wait's roughtly 15ms on my system
Thread.Sleep(3); // wait's roughtly 15ms on my system

}

IHTH

- Per

Reply to this message...
 
    
Willy Denoyette [MVP] (VIP)
Per ,

I'm sorry, but this is not correct, Thread.Sleep uses OS Kernel Waitable
timer objects who have a resolution of 1 msec., It's not using the
multimedia timer service nor the system timer.

If this were true , following
timeBeginPeriod(10000);
Thread.Sleep(1);
would sleep 10 sec.

I wonder how you measured the sleep time on your system (sepecially those
below 10 msec).

Willy.

"Per Larsen" <perATportablemindsDOTcom> wrote in message
news:Click here to reveal e-mail address...
[Original message clipped]

Reply to this message...
 
    
Per Larsen
Willy,

[Original message clipped]

Not on my system (XP/Pro/sp1) (the resolution, that is - I don't claim to
know how it's actually implemented).

[Original message clipped]

I haven't tried it for anything above 50 mSecs, or so, so you could be
right. Isn't there an upper limit on what timeBeginPeriod supports anyway?

[Original message clipped]

QueryPerformanceCounter, but I won't keep you guessing at what I'm doing :)
You'll find my test code (that happened to still have lying around) below.
Try running the test as it is first, then comment out the call to
timeBeginPeriod and run it again.

Here are my results. Req is the argument to Sleep, Avg, Max, and Min are the
measured results.

With call to timeBeginPeriod:

Req:0 Avg:0.004 Max:0.256 Min:0
Req:1 Avg:1.96 Max:2.551 Min:1.613
Req:2 Avg:3.005 Max:11.561 Min:2.11
Req:3 Avg:3.904 Max:4.074 Min:3.743
Req:4 Avg:4.88 Max:4.917 Min:4.787
Req:5 Avg:5.857 Max:5.869 Min:5.768
Req:6 Avg:6.833 Max:6.933 Min:6.735
Req:7 Avg:7.81 Max:7.881 Min:7.711
Req:8 Avg:8.786 Max:8.823 Min:8.692
Req:9 Avg:9.763 Max:9.971 Min:9.565
Req:10 Avg:10.739 Max:10.749 Min:10.642
Req:11 Avg:11.716 Max:11.754 Min:11.617
Req:12 Avg:12.692 Max:12.708 Min:12.585
Req:13 Avg:13.669 Max:13.768 Min:13.569
Req:14 Avg:14.645 Max:14.657 Min:14.551
Req:15 Avg:15.622 Max:15.635 Min:15.533
Req:16 Avg:16.598 Max:16.68 Min:16.515
Req:17 Avg:17.575 Max:17.615 Min:17.483
Req:18 Avg:18.551 Max:18.57 Min:18.459
Req:19 Avg:19.528 Max:19.538 Min:19.426
Press <CR>

Without call to timeBeginPeriod:

Req:0 Avg:0.004 Max:0.258 Min:0
Req:1 Avg:15.541 Max:16.899 Min:7.66
Req:2 Avg:15.621 Max:15.788 Min:15.456
Req:3 Avg:15.622 Max:15.785 Min:15.464
Req:4 Avg:15.622 Max:15.811 Min:15.433
Req:5 Avg:15.622 Max:15.99 Min:15.264
Req:6 Avg:15.622 Max:15.719 Min:15.525
Req:7 Avg:15.622 Max:15.722 Min:15.523
Req:8 Avg:15.622 Max:15.956 Min:15.294
Req:9 Avg:15.622 Max:15.721 Min:15.526
Req:10 Avg:15.622 Max:15.721 Min:15.533
Req:11 Avg:15.622 Max:15.954 Min:15.304
Req:12 Avg:15.623 Max:15.724 Min:15.537
Req:13 Avg:15.621 Max:16.023 Min:15.291
Req:14 Avg:15.622 Max:15.93 Min:15.33
Req:15 Avg:15.622 Max:15.874 Min:15.373
Req:16 Avg:31.246 Max:31.512 Min:30.915
Req:17 Avg:31.246 Max:31.324 Min:31.128
Req:18 Avg:31.246 Max:31.581 Min:30.923
Req:19 Avg:31.246 Max:31.341 Min:31.16
Press <CR>

If I'm doing something wrong here, I'll be very interested to learn what it
is.
My system is a Dell 8300 P4@3GHz, in case that matters. Hyperthreading is
not enabled.
Oh, and I'm running this from within VS.NET1.1.

- Per

Waiter.cs:
-------------------------------------------------
using System;
using System.Runtime.InteropServices;
using System.Threading;
namespace WaitTest
{
/// <summary>
/// Summary description for Waiter.
/// </summary>
public class Waiter
{
internal const String WINMM = "winmm.dll";
internal const String KERNEL32 = "kernel32.dll";
[DllImport(WINMM)]
internal static extern uint timeBeginPeriod(
uint period);
[DllImport(WINMM)]
internal static extern uint timeEndPeriod(
uint period);
[DllImport(KERNEL32)]
internal static extern bool QueryPerformanceCounter(
out long PerformanceCount);
[DllImport(KERNEL32)]
internal static extern bool QueryPerformanceFrequency(
out long Frequency);
internal static long Freq;
static Waiter()
{
timeBeginPeriod(1);
QueryPerformanceFrequency(out Freq);
}
~Waiter()
{
timeEndPeriod(1);
}
static public long GetTimestamp()
{
long result;
QueryPerformanceCounter(out result);
return result;
}
static public long DeltaMilliseconds(long earlyTimestamp, long
lateTimestamp)
{
return (((lateTimestamp - earlyTimestamp) * 1000) / Freq);
}
static public long DeltaMicroseconds(long earlyTimestamp, long
lateTimestamp)
{
return (((lateTimestamp - earlyTimestamp) * 1000000) / Freq);
}
static public void Wait(int delay)
{
long Elapsed = 0;
long Before = GetTimestamp();
while (delay > Elapsed)
{
System.Threading.Thread.Sleep(delay);
Elapsed = DeltaMilliseconds(Before, GetTimestamp());
}
}
}
}
-------------------------------------------------

Class1.cs:
-------------------------------------------------
using System;
namespace WaitTest
{
/// <summary>
/// Summary description for Class1.
/// </summary>
class Class1
{
/// <summary>
/// The main entry point for the application.
/// </summary>
[STAThread]
static void Main(string[] args)
{
int MaxDelay = 20;
int MaxLoopCount = 100;
for (int delay = 0; delay < MaxDelay; delay++)
{
long Total = 0;
long Max = 0;
long Min = 0;
for (int loopCount = 0; loopCount < MaxLoopCount; loopCount++)
{
long start = Waiter.GetTimestamp();
Waiter.Wait(delay);
long end = Waiter.GetTimestamp();
long actualDelay = Waiter.DeltaMicroseconds(start, end);
if (loopCount == 0)
{
Max = actualDelay;
Min = actualDelay;
}
else
{
if (actualDelay > Max)
Max = actualDelay;
if (actualDelay < Min)
Min = actualDelay;
}
Total += actualDelay;
}
Console.WriteLine("Req:{0} Avg:{1} Max:{2} Min:{3}",
delay, Total / MaxLoopCount / 1000.0, Max / 1000.0, Min / 1000.0);
}
Console.WriteLine("Press <CR>");
Console.ReadLine();
}
}
}
-------------------------------------------------

Reply to this message...
 
 
System.Console
System.Threading.Thread




Ad
MBR BootFX
Best-of-breed application framework for .NET projects, developed by Matthew Baxter-Reynolds and MBR IT
 
 Copyright © Matthew Baxter-Reynolds 2001-2008. '.NET 247 Software Development Services' is a trading style of MBR IT Solutions Ltd.
Contact Us - Terms of Use - Privacy Policy - www.dotnet247.com