0

I write a c# program to count down 5 seconds. What I do is:

        new Task(() =>
        {

                try
                {
                        this.Invoke((Action)delegate()
                        {
                            label1.Text = "5"; // 4, 3, 2..etc
                        });
                    }
                    Thread.Sleep(1000);
                }
                catch
                {
                    // form could be disposed
                    break;
                }

            }

        }).Start();

This works on my PC, however, when I copied the program to a window tablet, the Thread.Sleep(1000) gives more than 1 second. In other words, it takes more than 5 seconds (in fact more than 10 seconds) to update the label from 5,4,3,2,1. Alternatively, it takes too long to update label1.Text = "5", etc? It does not make sense to me. I wonder what is wrong?

manhon
  • 683
  • 7
  • 27
  • Nothing is wrong. `Thread.Sleep(n)` guarantees, that _your thread would not be notified/waked up before_ `n` milliseconds pass, and nothing more. Have your thread bean woken up before `n` milliseconds passed? No. `Thread.Sleep(n)` worked just fine. – mg30rg Mar 31 '15 at 10:17

2 Answers2

7

Sleep will wait at least that long before activating the thread again, but it can always be longer than that. After the one second time has passed the thread becomes eligible to execute by the CPU scheduler, and the scheduler is able to run it whenever it wants to. If it's particularly busy, and/or is using a scheduling algorithm that doesn't focus on quickly allowing newly active threads to run, it could be some time.

Servy
  • 202,030
  • 26
  • 332
  • 449
5

Servy's answer is correct. For more details, please read the documentation:

https://msdn.microsoft.com/en-us/library/windows/desktop/ms686298.aspx

which states:

Note that a ready thread is not guaranteed to run immediately. Consequently, the thread may not run until some time after the sleep interval elapses. For more information, see Scheduling Priorities.

The priority documentation is here:

https://msdn.microsoft.com/en-us/library/windows/desktop/ms685100.aspx

More generally though: you are doing something deeply wrong. Do not ever use Sleep like this. If you want to wait some amount of time then use a timer or use a Delay task. Never sleep a thread like this outside of test code. The right way to write your code is probably something like

for (int countdown = 5; countdown > 0; countdown -= 1)
{
    label1.Text = countdown.ToString();
    await Task.Delay(1000);
}

Or, make a class that has a timer and a counter, start the timer to tick a few times a second, compare the current time to the time when you last updated the label, and if more than a second has elapsed, update the label.

Eric Lippert
  • 647,829
  • 179
  • 1,238
  • 2,067
  • And of course CPU scheduling algorithms are going to be OS dependent, rather than being uniform for all C# programs. C# code running on, say, Mono in a Unix OS will have different scheduling characteristics. – Servy Mar 30 '15 at 17:23
  • When you say "Never sleep a thread like this outside of test code," are you recommending that all instances of `Thread.Sleep` be replaced with a `Delay` task, or does this just apply in a UI context? – BJ Myers Mar 30 '15 at 17:56
  • 2
    @nintendojunkie: `Sleep` is not a great example of method design. It has special-purpose cases; `Sleep(0)` has a very different meaning than `Sleep(1)` for instance. It is documented as not providing a guarantee on the actual time slept; it can sleep more or less time than the argument given. It does not pump messages, so it introduces hangs in applications. And it utterly wastes a thread, an expensive resource. It is almost never used correctly, and it really should be avoided unless you have a truly compelling reason to use it. – Eric Lippert Mar 30 '15 at 18:07
  • Interesting. I might post a follow-up question on this. – BJ Myers Mar 30 '15 at 18:08