1

So I have thrown together a quick repro to highlight the issue while helping myself to understand what on earth was going on in my main app, after receiving many user reports of sudden slow behaviour out of nowhere after more than a year without issue. An active user of my application pointed out that the problem only came about after a recent Windows update, it led me to verify that it was indeed caused by the October Update 20H2.

using System;
using System.Diagnostics;
using System.Threading;
using System.Windows.Forms;

namespace SleepRepro
{
    public partial class Form1 : Form
    {
        public Form1()
        {
            InitializeComponent();
        }

        private void startButton_Click(object sender, EventArgs e)
        {
            Stopwatch sw = new Stopwatch();
            sw.Start();
            new Thread(() =>
            {
                Thread.Sleep(5);
                Log("Sleep took " + sw.ElapsedMilliseconds + "ms");
            }).Start();
        }

        public void Log(string str)
        {
            Invoke((MethodInvoker)delegate
            {
                logTextBox.Text += str + Environment.NewLine;
                logTextBox.SelectionStart = logTextBox.Text.Length;
                logTextBox.ScrollToCaret();
            });
        }
    }
}

It appears there is a new loss of precision in Thread.Sleep?

Sleep Repro 20H2

I guess my question is whether or not this is intended behaviour or a bug? Is there some documentation of it somewhere?

Thanks in advance.

Spark
  • 1,007
  • 1
  • 8
  • 26
  • 4
    You never called `timeBeginPeriod()` so you are getting the default timer resolution that was set by whatever other programs were running that *did* request a specific timer resolution. [Further discussion of recent timer changes](https://randomascii.wordpress.com/2020/10/04/windows-timer-resolution-the-great-rule-change/). – Raymond Chen Nov 01 '20 at 15:13
  • One of the reasons why you shouldn't add random sleeps to wait for things to be done – Camilo Terevinto Nov 01 '20 at 15:31
  • @RaymondChen: DIdn't know that. What a weird construction that is. Thanks fot the info! – Paul Sinnema Nov 01 '20 at 15:50
  • Thanks for this @RaymondChen I suspect there will be many developers seeking this info over the coming months, which I was unable to find. I had thrown together a sleep wrapper function in my main application that checked state every 5 milliseconds during the sleep, in order to cancel a sleep if required. Although that is probably a terrible design choice and thus entirely my fault, this windows update basically crippled my application :( – Spark Nov 01 '20 at 16:07
  • It's not that easy (for me) to imagine situation when this relatively minor innacuracy in thread sleep leads to user-noticeable slowdown of entire application. – Evk Nov 01 '20 at 16:27
  • 1
    Your program was already unreliable. It was inadvertently relying on Chrome or Spotify increasing the timer resolution. If a customer ran your program on a clean system they would've gotten 15ms delays, too. So not a new problem. – Raymond Chen Nov 01 '20 at 17:01
  • @Evk I was repeatedly sleeping in intervals of 5ms to make up a total sleep duration, while checking if I should stop sleeping based on a stop signal. This quickly turns an attempted 2000ms sleep into a ~6248ms sleep, furthermore, if you foolishly use the same sleep wrapper all over your application, you quickly see the problem. Raymond Chen Lesson learnt, thank you for your help. Hopefully others will find this useful too. – Spark Nov 01 '20 at 17:25
  • You should be tracking the total elapsed time and stop when the total elapsed time reaches 2000ms. Sleep() is allowed to run long. Even if it didn't, the thread could get pre-empted (say by GC or a page fault or a higher priority thread) and not run for a while, which would add to the time spent in the loop. – Raymond Chen Nov 02 '20 at 05:03
  • See [this Q&A](https://stackoverflow.com/q/64514787/1889329). On a personal note, I find it refreshing that Microsoft have finally accepted, that broken code is permitted to change its observable behavior across system updates. – IInspectable Nov 02 '20 at 07:27

0 Answers0