Как заставить поток спать меньше миллисекунды в Windows

В Windows у меня есть проблема, с которой я никогда не сталкивался в Unix. Вот как перевести поток в спящий режим менее чем на одну миллисекунду. В Unix у вас обычно есть несколько вариантов (сон, usleep и nanosleep) в соответствии с вашими потребностями. В Windows, однако, есть только Спать с точностью до миллисекунды.

В Unix я могу использовать системный вызов select для создания микросекундного сна, что довольно просто:

int usleep(long usec)
{
    struct timeval tv;
    tv.tv_sec = usec/1000000L;
    tv.tv_usec = usec%1000000L;
    return select(0, 0, 0, 0, &tv);
}

Как я могу добиться того же в Windows?

Это не работает в Windows. Минимальное время "сна" при выборе по-прежнему составляет около 1 мс (Vista, поток RT, timeBeginPeriod (1), MMCSS "Pro Audio" RT Critical).

Robert 20.07.2011 20:54

Это связано с тем, что большинство компьютеров, на которых работает Windows, имеют аппаратные ограничения в диапазоне 1-10 мс. Компьютерное оборудование для ПК стоит дешево. Вам понадобится специализированное оборудование, чтобы следить за точным временем. Например, карты Wi-Fi: время передачи маяка в миллисекундах должно оставаться аппаратным (даже в Linux) из-за ненадежности хронометража ПК.

unixman83 22.09.2011 01:14
Linux can run on complex and embedded devices, which can provide for better granularity than most Windows PCs. The kernel itself, being open source, is also very customizable. Its scheduler can be made a почти в реальном времени OS. Hence the need for nanosleep().
unixman83 22.09.2011 01:18

Возможный дубликат Требуется точный сон потока. Ошибка макс. 1 мс

ivan_pozdeev 12.08.2017 15:37
Стоит ли изучать PHP в 2026-2027 годах?
Стоит ли изучать PHP в 2026-2027 годах?
Привет всем, сегодня я хочу высказать свои соображения по поводу вопроса, который я уже много раз получал в своем сообществе: "Стоит ли изучать PHP в...
Поведение ключевого слова "this" в стрелочной функции в сравнении с нормальной функцией
Поведение ключевого слова "this" в стрелочной функции в сравнении с нормальной функцией
В JavaScript одним из самых запутанных понятий является поведение ключевого слова "this" в стрелочной и обычной функциях.
Приемы CSS-макетирования - floats и Flexbox
Приемы CSS-макетирования - floats и Flexbox
Здравствуйте, друзья-студенты! Готовы совершенствовать свои навыки веб-дизайна? Сегодня в нашем путешествии мы рассмотрим приемы CSS-верстки - в...
Тестирование функциональных ngrx-эффектов в Angular 16 с помощью Jest
В системе управления состояниями ngrx, совместимой с Angular 16, появились функциональные эффекты. Это здорово и делает код определенно легче для...
Концепция локализации и ее применение в приложениях React ⚡️
Концепция локализации и ее применение в приложениях React ⚡️
Локализация - это процесс адаптации приложения к различным языкам и культурным требованиям. Это позволяет пользователям получить опыт, соответствующий...
Пользовательский скаляр GraphQL
Пользовательский скаляр GraphQL
Листовые узлы системы типов GraphQL называются скалярами. Достигнув скалярного типа, невозможно спуститься дальше по иерархии типов. Скалярный тип...
58
4
81 883
18
Перейти к ответу Данный вопрос помечен как решенный

Ответы 18

Ответ принят как подходящий

В Windows использование select вынуждает вас включить библиотеку Winsock, которая должна быть инициализирована в вашем приложении следующим образом:

WORD wVersionRequested = MAKEWORD(1,0);
WSADATA wsaData;
WSAStartup(wVersionRequested, &wsaData);

И тогда выбор не позволит вам вызываться без какого-либо сокета, поэтому вам нужно сделать немного больше, чтобы создать метод микросна:

int usleep(long usec)
{
    struct timeval tv;
    fd_set dummy;
    SOCKET s = socket(PF_INET, SOCK_STREAM, IPPROTO_TCP);
    FD_ZERO(&dummy);
    FD_SET(s, &dummy);
    tv.tv_sec = usec/1000000L;
    tv.tv_usec = usec%1000000L;
    return select(0, 0, 0, &dummy, &tv);
}

Все эти созданные методы usleep возвращают ноль в случае успеха и ненулевое значение в случае ошибок.

Эта имплантация Sleep () пропускает сокет каждый раз, когда он вызывается!

Jeremy Friesner 25.03.2015 00:46

Этот метод «спит» около 15 миллисекунд, даже если запрошен только 1 микросекундный спящий режим.

Serge Rogatch 18.09.2015 15:00

Вам не нужно создавать сокет для вызова select (). Пожалуйста, удалите этот ответ.

craig65535 27.01.2016 03:48

Это копирует реализацию, но не семантику. Вы не можете реализовать задержку с продолжительностью меньше, чем частота таймера. Извините, это бесполезно и вводит в заблуждение. По крайней мере, отмените выбор этого ответа как принятого. Конечно, поскольку вы никогда не решались задать вопрос, любой ответ был бы одинаково хорош, если бы он никогда не вводил в заблуждение.

IInspectable 07.07.2016 14:36

Это указывает на неправильное понимание функций сна. Передаваемый вами параметр - это время сна минимум. Нет никакой гарантии, что поток проснется точно в указанное время. Фактически, потоки вообще не «просыпаются», а выбираются для выполнения планировщиком ОС. Планировщик может выбрать ожидание намного дольше, чем запрошенная продолжительность сна, чтобы активировать поток, особенно если другой поток все еще активен в этот момент.

Да, Sleep () означает просто подсказку. Согласно MSDN время Sleep () на самом деле может быть меньше, чем то, что вы запрашиваете. Это просто руководство для ОС по повышению производительности, а не совсем хороший механизм синхронизации при степени детализации любой.

unixman83 22.09.2011 01:08

Однако гарантию можно получить при тщательной реализации. Правильная установка приоритетов потоков / процессов и сходства процессоров обсуждается здесь.

Arno 26.09.2012 20:17

Здесь есть серьезная дезинформация: «Передаваемый вами параметр - минимальное время сна». Не актуально для окон: msdn.microsoft.com/en-gb/library/windows/desktop/…Если dwMilliseconds меньше разрешения системных часов, поток может спать меньше указанного промежутка времени. Если dwMilliseconds больше одного тика, но меньше двух, ожидание может составлять от одного до двух тиков и так далее.

Roddy 07.11.2012 23:33

Отличный ответ на несуществующий вопрос. Несмотря на то, что все ответы ни на один вопрос верны, этот действительно хорош.

Kenyakorn Ketsombut 11.09.2013 11:27

Это просто не отвечает на вопрос. Это хороший ответ на другой вопрос, поэтому я очень не хочу давать вам голос против, но слишком многие ошибочно проголосовали за вас. Если бы вы сказали «не можете, и вот почему», вы бы ответили на вопрос.

John Thoits 25.01.2019 22:37

Как говорит Джоэл, вы не можете осмысленно «спать» (то есть отказываться от запланированного CPU) в течение таких коротких периодов времени. Если вы хотите отложить на короткое время, вам нужно вращаться, неоднократно проверяя таймер с подходящим высоким разрешением (например, «таймер производительности») и надеясь, что что-то с высоким приоритетом все равно вас не упустит.

Если вы действительно заботитесь о точных задержках в такие короткие промежутки времени, вам не следует использовать Windows.

-1 за то, что не учитывает, что пользователь приложения может иметь другие предпочтения, чем разработчики.

Austin Mullins 12.06.2014 18:34

@AustinMullins Не могли бы вы немного рассказать об этом? Вы искали какое-нибудь заявление о пороках занятого прядения?

Will Dean 18.06.2014 15:48

Нет, я имел в виду замечание «вам не следует использовать Windows». Разработчик должен делать программы для пользователя, который, вероятно, хочет, чтобы программа работала в Windows.

Austin Mullins 18.06.2014 15:59

А ну понятно. Что ж, если разработчик или его пользователи предвидят требование жесткого реального времени, как описано в вопросе, тогда Windows не та ОС, которую им следует пытаться использовать. Это не уничижительный комментарий к Windows и не лицензия на высокомерие разработчиков, это просто мнение о технической пригодности, которое (как разработчик Windows :-) я рад поддержать.

Will Dean 18.06.2014 18:28

Я один из разработчиков, использующих окна принужденный, потому что нашему приложению необходимо взаимодействовать с другим, доступным также в Windows. После моих тестов я согласен с этим решением, которое дало нам наилучшие результаты, но я категорически не согласен с вашим последним предложением «вам не следует использовать Windows»: вы не можете знать, почему разработчику нужно спать для суб- Интервал мс. Про этот здесь есть даже целый проект

gog 24.09.2018 14:56

@gog - Вы не можете надежно засыпать (или задерживать любым другим способом) на такое короткое время в Windows (кроме, возможно, написания драйвера режима ядра). Неважно, какие еще коммерческие или прагматические требования делают Windows хорошим выбором, она просто не предназначена для такого рода вещей. Как я неоднократно повторял за 10 лет, прошедших с тех пор, как написал первоначальный ответ, это не критика, это наблюдение. Ваш жесткий цикл может большую часть времени ждать нужного времени, но иногда он будет ждать дольше, и если вы не можете этого допустить, Когда-либо не сможет использовать Windows.

Will Dean 24.09.2018 19:42

@WillDean Но, используя ваше решение (QueryPerformanceCounter), я смог спать в течение микросекунд в Windows, так же, как это доступно в Unix. Это исходный вопрос. Вопрос не касается RTOS, где приложение никогда не может выдерживать более длительный сон. Даже Sleep () не может этого гарантировать. И даже ядро ​​Linux в стандартных дистрибутивах не гарантирует этого. Я думаю, что последнее предложение не относится к этому ответу, даже если я проголосовал за него.

gog 27.09.2018 15:56

Используйте мультимедийные таймеры высокого разрешения, доступные в winmm.lib. См. Пример это.

Я удивлен, что за это не проголосовали больше. Это реальное решение. Почему все голосуют за «Сон - это всего лишь предположение» и «Прекратите использовать Windows, переключитесь на Unix»? Я признаю, что полезно понимать, что сон - это всего лишь предположение, но это не решение. И не у всех есть возможность выйти из Windows. Чтобы быть ясным, это решение дает вам точность только 1 мс (с использованием библиотеки мультимедиа). Это то что мне нужно. Я не пробовал технику «выбора» (опубликованную Хендриком и Сминком), но похоже, что она может снизить точность до субмиллисекунд.

Gabe Halsmer 08.08.2015 20:56

Связанный код @GabeHalsmer может ждать только 1 или более мсек, это не то, о чем спрашивают. Более того, он не компилируется из коробки, содержит ошибки и не является потокобезопасным и может либо вызывать тупиковые ситуации, либо вообще не ждать. Даже после исправления некоторых проблем, чтобы заставить его делать то, что он должен делать, и просить его подождать 1 мс, я видел, как он ждал где-то от 1 до 3 мс, и это были просто быстрые тесты в системе без большой нагрузки. Таким образом, он не работает лучше, а хуже, чем более простая комбинация WaitableTimer / WaitForSingleObject путь, которая, по крайней мере, выполняет ожидания sub-mSec. Итак: не совсем подходящее решение для всех.

stijn 10.05.2017 10:44

Все комментарии, относящиеся к Linux, должны быть помечены и удалены. @Gabe, вы правы, пользователи ОС с рыночной долей в 1% часто пытаются шуметь.

Michael Chourdakis 23.07.2020 13:34

Что вы ждете, что требует такой точности? В общем, если вы необходимость для указания этого уровня точности (например, из-за зависимости от некоторого внешнего оборудования), вы находитесь на неправильной платформе и должны смотреть на ОС реального времени.

В противном случае вам следует подумать, есть ли событие, с которым вы можете синхронизироваться, или, в худшем случае, просто занято, дождитесь процессора и используйте API счетчика высокой производительности для измерения прошедшего времени.

Да, вам нужно понимать кванты времени вашей ОС. В Windows вы даже не получите время разрешения 1 мс, если не измените квант времени на 1 мс. (Используя, например, timeBeginPeriod () / timeEndPeriod ()) Это все равно ничего не гарантирует. Даже небольшая загрузка или один дрянной драйвер устройства все скинут.

SetThreadPriority () помогает, но довольно опасно. Плохие драйверы устройств могут вас испортить.

Вам нужна сверхуправляемая вычислительная среда, чтобы эта уродливая штука вообще работала.

Вы просто должны быть осторожны, чтобы не зацикливаться, иначе другие процессы будут голодны ...

rogerdpack 16.11.2019 02:35

Я в основном говорил о других вещах, которые вы здесь не контролируете. Довольно легко получить что-то, что работает на одном компьютере, полностью выйдет из строя на другом, потому что плохой драйвер устройства держится слишком долго. Если вы разрабатываете что-то для внутреннего использования, это нормально ... если вам нужно что-то, что вы можете выпустить в мир, это действительно болезненно.

darron 14.12.2019 19:16

Попробуйте boost :: xtime и timed_wait ()

имеет наносекундную точность.

Вы путаете точность с точностью.

IInspectable 07.07.2016 14:40

Как указали несколько человек, сон и другие связанные функции по умолчанию зависят от «системного тика». Это минимальная единица времени между задачами ОС; например, планировщик не будет работать быстрее этого. Даже в ОС реального времени системный тик обычно составляет не менее 1 мс. Хотя он настраивается, это имеет последствия для всей системы, а не только для вашей функции сна, потому что ваш планировщик будет работать чаще и потенциально увеличивает накладные расходы вашей ОС (количество времени для запуска планировщика по сравнению с количеством время выполнения задачи).

Решением этого является использование внешнего высокоскоростного тактового устройства. Большинство систем Unix позволяют вам указывать свои таймеры и такие разные часы для использования, в отличие от системных часов по умолчанию.

Если вам нужна такая степень детализации, вы находитесь не в том месте (в пространстве пользователя).

Помните, что если вы находитесь в пользовательском пространстве, ваше время не всегда точно.

Планировщик может запускать ваш поток (или приложение) и планировать его, поэтому вы зависите от планировщика ОС.

Если вы ищете что-то точное, вам нужно пойти: 1) В пространстве ядра (например, в драйверах) 2) Выберите RTOS.

В любом случае, если вы ищете некоторую детализацию (но помните о проблеме с пользовательским пространством), посмотрите Функция QueryPerformanceCounter и функция QueryPerformanceFrequency в MSDN.

Просто используйте Sleep (0). 0 явно меньше миллисекунды. Звучит смешно, но я серьезно. Sleep (0) сообщает Windows, что вам сейчас нечего делать, но вы действительно хотите, чтобы вас пересмотрели, как только планировщик снова запустится. И поскольку очевидно, что выполнение потока нельзя запланировать до запуска самого планировщика, это самая короткая возможная задержка.

Обратите внимание, что вы можете передать в usleep число в микросекундах, но это также означает void usleep (__ int64 t) {Sleep (t / 1000); } - нет никаких гарантий, что вы действительно спите в этот период.

Я думаю, что если вы действительно попробуете это, вы обнаружите, что Sleep (0) обычно спит в течение 10-15 мс в зависимости от вашего оборудования и загрузки системы.

Dave Moore 19.09.2008 04:02

Из MSDN: нулевое значение заставляет поток передать оставшуюся часть своего временного интервала любому другому потоку с таким же приоритетом, который готов к запуску. Если нет других потоков с равным приоритетом, готовых к запуску, функция немедленно возвращается, и поток продолжает выполнение.

Ferruccio 24.09.2008 14:20

Последняя часть ответа неверна. Если вы разделите int на 1000, тогда любое значение ниже 1000 будет установлено в 0. Таким образом, ваша функция usleep просто вызовет Sleep (0) для любого значения меньше миллисекунды. И, как сказал @Ferruccio, Sleep (0) не спит меньше миллисекунды, здесь это опасность.

xryl669 10.01.2017 21:18

У меня такая же проблема, и ничто не работает быстрее, чем мс, даже Sleep (0). Моя проблема заключается в связи между клиентским и серверным приложением, где я использую функцию _InterlockedExchange для тестирования и установки бита, а затем я сплю (0).

Мне действительно нужно выполнять тысячи операций в секунду таким образом, и он работает не так быстро, как я планировал.

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

Чтобы вы, ребята, поняли, насколько медленным является этот сон, я провел тест в течение 10 секунд, выполняя пустой цикл (получилось что-то вроде 18 000 000 циклов), тогда как при наличии события у меня было только 180 000 циклов. То есть в 100 раз медленнее!

Меня не удивляет. Поскольку пустой цикл будет выполняться во внутреннем кэше процессора, когда он пуст. Меня не удивит, если компилятор даже оптимизирует цикл и просто выдаст вам результат. Лучший тест, который на самом деле что-то делает в обоих случаях, и сравнивает результат. попробуйте выполнить _InterlockedIncrement (внутренний) при каждом взаимодействии обоих циклов.

rxantos 06.08.2015 18:48

Фактически использование этой функции usleep приведет к большой утечке памяти / ресурсов. (в зависимости от того, как часто звонят)

используйте эту исправленную версию (извините, не можете редактировать?)

bool usleep(unsigned long usec)
{
    struct timeval tv;
    fd_set dummy;
    SOCKET s = socket(PF_INET, SOCK_STREAM, IPPROTO_TCP);
    FD_ZERO(&dummy);
    FD_SET(s, &dummy);
    tv.tv_sec = usec / 1000000ul;
    tv.tv_usec = usec % 1000000ul;
    bool success = (0 == select(0, 0, 0, &dummy, &tv));
    closesocket(s);
    return success;
}

Вам не нужно создавать сокет только для того, чтобы иметь возможность вызывать select ()

Jon Watte 09.09.2012 04:35

Я исправил образец кода. Имейте в виду, что вы должны вызвать WSAStartup / WSACleanup до / после использования этой функции при кодировании под Windows.

Max Truxa 07.08.2013 11:26

Как уже упоминалось, действительно нет никаких гарантий относительно времени сна. Но никто не хочет признавать, что иногда в простаивающей системе команда usleep может быть очень точной. Особенно с бестикальным ядром. Он есть в Windows Vista, а в Linux - начиная с версии 2.6.16.

Бесконтактные ядра существуют, чтобы помочь улучшить жизнь ноутбуков: ср. Утилита Intel powertop.

В этом состоянии я случайно измерил команду Linux usleep, которая очень точно соблюдает запрошенное время сна, до полдюжины микросекунд.

Так что, возможно, OP хочет что-то, что будет грубо работать большую часть времени в системе на холостом ходу, и иметь возможность запрашивать планирование микросекунд! На самом деле я бы тоже хотел этого в Windows.

Также Sleep (0) звучит как boost :: thread :: yield (), что терминология более ясна.

Интересно, имеют ли блокировки с синхронизацией Способствовать росту более высокую точность. Потому что тогда вы можете просто заблокировать мьютекс, который никто никогда не выпускает, а когда истечет время ожидания, продолжить ... Таймауты устанавливаются с помощью boost :: system_time + boost :: milliseconds & cie (xtime не рекомендуется).

Обычно сон длится, по крайней мере, до следующего системного прерывания. Однако это зависит от настроек ресурсов мультимедийного таймера. Это может быть что-то близкое к 1 мс, некоторое оборудование даже позволяет работать с периодами прерывания 0,9765625 (Фактическое разрешение, предоставленный NtQueryTimerResolution, покажет 0,9766, но это на самом деле неверно. Они просто не могут поместить правильное число в формат Фактическое разрешение. Это 0,9765625 мс при 1024 прерываниях в секунду) .

Есть одно исключение, которое позволяет нам избежать того факта, что может быть невозможно спать меньше периода прерывания: это знаменитый Sleep(0). Это очень мощный инструмент и используется не так часто, как нужно! Он отказывается от напоминания о временном интервале потока. Таким образом, поток остановится до тех пор, пока планировщик не заставит поток снова получить службу процессора. Sleep(0) - асинхронная служба, вызов заставит планировщик реагировать независимо от прерывания.

Второй способ - использование waitable object. Функция ожидания, такая как WaitForSingleObject(), может ждать события. Чтобы поток был спящим в течение любого времени, в том числе в микросекундном режиме, потоку необходимо настроить некоторый служебный поток, который будет генерировать событие с желаемой задержкой. «Спящий» поток настроит этот поток, а затем остановится в функции ожидания, пока служебный поток не установит сигнальное событие.

Таким образом, любой поток может «спать» или ждать в любое время. Сервисный поток может быть очень сложным и предлагать общесистемные сервисы, такие как синхронизированные события с микросекундным разрешением. Однако разрешение в микросекундах может вынудить поток службы вращаться на службе времени с высоким разрешением не более одного периода прерывания (~ 1 мс). Если соблюдать осторожность, это может работают очень хорошо, особенно на многопроцессорных или многоядерных системах. Вращение в одну мс не сильно повредит в многоядерной системе, когда маска сродства для вызывающего потока и потока службы тщательно обрабатывается.

Код, описание и тестирование можно найти на Проект отметки времени Windows

Попробуйте использовать SetWaitableTimer ...

#include <Windows.h>

static NTSTATUS(__stdcall *NtDelayExecution)(BOOL Alertable, PLARGE_INTEGER DelayInterval) = (NTSTATUS(__stdcall*)(BOOL, PLARGE_INTEGER)) GetProcAddress(GetModuleHandle("ntdll.dll"), "NtDelayExecution");
static NTSTATUS(__stdcall *ZwSetTimerResolution)(IN ULONG RequestedResolution, IN BOOLEAN Set, OUT PULONG ActualResolution) = (NTSTATUS(__stdcall*)(ULONG, BOOLEAN, PULONG)) GetProcAddress(GetModuleHandle("ntdll.dll"), "ZwSetTimerResolution");

static void SleepShort(float milliseconds) {
    static bool once = true;
    if (once) {
        ULONG actualResolution;
        ZwSetTimerResolution(1, true, &actualResolution);
        once = false;
    }

    LARGE_INTEGER interval;
    interval.QuadPart = -1 * (int)(milliseconds * 10000.0f);
    NtDelayExecution(false, &interval);
}

Очень хорошо подходит для очень короткого сна. Однако помните, что в определенный момент фактические задержки никогда не будут согласованными, потому что система не может поддерживать согласованные задержки в такое короткое время.

Интересный факт: timeBeginPeriod / timeEndPeriod внутренне использует ZwSetTimerResolution, и еще один интересный факт - минимальное временное разрешение составляет 0,5 мс, с timeBeginPeriod вы получите минимум 1 мс, но с ZwSetTimerResolution вы можете получить 0,5 мс, поэтому вызов ZwSetTimerResolution с 1 эквивалентен его вызову. с 5000 и ниже. (Это в блоке 100 нс, или ограничении 10 МГц)

rez 24.12.2020 12:34

Функция сна, которая длится меньше миллисекунды - возможно

Я обнаружил, что у меня работает sleep (0). В системе с почти 0% загрузкой процессора в диспетчере задач я написал простую консольную программу, и функция sleep (0) спала в течение последовательных 1-3 микросекунд, что намного меньше миллисекунды.

Но из приведенных выше ответов в этом потоке я знаю, что количество спящих сна (0) может варьироваться гораздо более дико, чем это в системах с большой загрузкой процессора.

Но как я понимаю, функцию сна не стоит использовать как таймер. Его следует использовать для того, чтобы программа использовала как можно меньше ресурсов процессора и выполнялась как можно чаще. Я думаю, что для моих целей, таких как перемещение снаряда по экрану в видеоигре, намного быстрее, чем один пиксель в миллисекунду, подойдет sleep (0).

Вы просто должны убедиться, что интервал сна намного меньше, чем наибольшее время, в течение которого он будет спать. Вы не используете спящий режим в качестве таймера, а просто для того, чтобы игра использовала минимально возможный процент процессора. Вы бы использовали отдельную функцию, которая не имеет ничего общего, это сон, чтобы узнать, когда прошло определенное количество времени, а затем переместить снаряд на один пиксель по экрану, скажем, за 1/10 миллисекунды или 100 микросекунд. .

Псевдокод будет выглядеть примерно так.

while (timer1 < 100 microseconds) {
sleep(0);
}

if (timer2 >=100 microseconds) {
move projectile one pixel
}

//Rest of code in iteration here

Я знаю, что ответ может не работать для сложных задач или программ, но может работать для некоторых или многих программ.

В играх вы не должны полагаться на тайминги кадров, вместо этого используйте скорость * тайминг. Таким образом, у вас не будет проблем, если компьютер будет перегружен.

Cem Kalyoncu 29.06.2016 10:30

@CemKalyoncu = или если тот же код будет запущен намного позже на значительно лучшем оборудовании. Я написал несколько старых рото-зумеров, систем частиц и различных эффектов для 386 и 486. Я уверен, вы можете представить, насколько непристойными они были при запуске на i3 (в одном случае от 20 кадров в секунду до более 700! !!)

enhzflep 22.10.2016 19:04

Если ваша цель - "подождать очень короткое время", потому что вы выполняете спинвейт, то уровни ожидания, которые вы можете выполнить, увеличиваются.

void SpinOnce(ref Int32 spin)
{
   /*
      SpinOnce is called each time we need to wait. 
      But the action it takes depends on how many times we've been spinning:

      1..12 spins: spin 2..4096 cycles
      12..32: call SwitchToThread (allow another thread ready to go on time core to execute)
      over 32 spins: Sleep(0) (give up the remainder of our timeslice to any other thread ready to run, also allows APC and I/O callbacks)
   */
   spin += 1;

   if (spin > 32)
      Sleep(0); //give up the remainder of our timeslice
   else if (spin > 12)
      SwitchTothread(); //allow another thread on our CPU to have the remainder of our timeslice
   else
   {
      int loops = (1 << spin); //1..12 ==> 2..4096
      while (loops > 0)
         loops -= 1;
   }
}

Итак, если ваша цель - дождаться только ненадолго, вы можете использовать что-то вроде:

int spin = 0;
while (!TryAcquireLock()) 
{ 
   SpinOne(ref spin);
}

Достоинство здесь в том, что мы каждый раз ждем дольше и в конечном итоге полностью засыпаем.

Другие вопросы по теме