Более точная альтернатива Thread.Sleep(1) - C#

Узнай цену своей работы

Формулировка задачи:

Как подсказывает мне гугл, Thread.Sleep - это зло во плоти, атата, руки оторвут, и т.д. Раньше проблем не было, пока не возникла следующая задача: мультипотоковое приложение c бесконечными циклами с настраиваемыми задержками шагом 1 мс. Принципиальная схема говнокодерская и выглядит так:
// класс-наследник от BackgroundWorker, переопределяет метод:
protected override void OnDoWork(DoWorkEventArgs e)
{
    while (true)
    {
        if (delay > 0)
        {
            stopwatch.Start();
            while (stopwatch.Elapsed.Milliseconds < delay)
            {
                Thread.Sleep(1);
            }
            stopwatch.Reset();
        }
 
        // обработка некоих данных, поступающих извне
 
        Thread.Sleep(1); //ради того, чтобы отпустить CPU и не грузить его на 100%
    }
}
Что было обнаружено:
But beware: Windows is not a real-time OS, so you will not get 1000 wakes per second from Thread.Sleep(1). If you haven't used timeBeginPeriod to set your minimum resolution you'll wake about every 15 ms.
И я вижу абсолютно такую же историю. Любая задержка от 1 до 15 включительно выглядит, как 15 мс. Разница начинает быть видна от 16 и далее. Кроме того, задержка самого потока тоже тормозит его работу на 15 мс в случае, если delay не равна нулю. Мне же нужно, чтобы поток реагировал с точностью в 1 мс, и чтобы дополнительную задержку можно было ставить с шагом 1 мс. Если вообще убрать sleep(1), всё работает безупречно. Скорость реакции потока на внешние раздражители, которые он и обрабатывает - десятая доля миллисекунды. Настройка доп.задержки - идеальная точность, плюс-минус десять тиков. НО. Поток грузит cpu. Вопрос - как добиться того, чтобы поток работал "почти" в реальном времени (с задержкой реакции 1 мс или меньше), дополнительная задержка работала с точностью 1 мс, но при этом поток не грузил CPU на 100% ?

Решение задачи: «Более точная альтернатива Thread.Sleep(1)»

textual
Листинг программы
using System;
using System.Threading;
using System.Timers;
using Timer = System.Timers.Timer;
 
namespace ConsoleApplication23
{
    class Program
    {
        private static int i = 0;
        static void Main(string[] args)
        {
            var timer = new Timer(1);
            timer.Elapsed += (_, __) =>
                             {
                                 if (i > 0)
                                     Console.WriteLine(i);
                             }; 
            timer.Start();
            Console.ReadKey();
        }
    }
}

ИИ поможет Вам:


  • решить любую задачу по программированию
  • объяснить код
  • расставить комментарии в коде
  • и т.д
Попробуйте бесплатно

Оцени полезность:

5   голосов , оценка 4.2 из 5