Сейчас на форуме: (+4 невидимых)

 eXeL@B —› Программирование —› Вопрос по циклу
Посл.ответ Сообщение

Ранг: 18.9 (новичок), 4thx
Активность: 0.030.05
Статус: Участник

Создано: 18 декабря 2019 22:40
· Личное сообщение · #1

Возникла необходимость в процедуре сделать задержку менее 1мс.
NtDelayExecution и WaitableTimer по непонятным причинам нивкакую не захотели делать задержку меньше, поэтому реализовал через высокоточный таймер ОС

Code:
  1. Цикл: пока (текущее значение) - (стартовое значение) < значение задержки: Sleep(0)


На этом можно было бы и остановиться, но все таки Sleep с нулевым значением грузит процессор и исходя из этого вопрос - есть ли альтернативный вызов не нагружающий CPU в подобном цикле?




Ранг: 338.5 (мудрец), 349thx
Активность: 2.112.42
Статус: Участник

Создано: 18 декабря 2019 22:56 · Поправил: difexacaw
· Личное сообщение · #2

А что толку от высокоточного таймера, если он никак не влияет на планирование(те на переключение задач).

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

> есть ли альтернативный вызов не нагружающий CPU в подобном цикле?

NtYieldExecution.

-----
vx




Ранг: 54.0 (постоянный), 49thx
Активность: 0.721.1
Статус: Участник

Создано: 18 декабря 2019 22:57 · Поправил: SDK
· Личное сообщение · #3

Ate пишет:
сделать задержку менее 1мс.

такая низкая задержка на видеокартах реализуется для игр Ate пишет:
NtDelayExecution и WaitableTimer по непонятным причинам нивкакую не захотели делать задержку меньше
у них 1мс это максимум что можно выжать



Ранг: 251.3 (наставник), 81thx
Активность: 0.140.11
Статус: Участник

Создано: 18 декабря 2019 23:46
· Личное сообщение · #4

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



Ранг: 18.9 (новичок), 4thx
Активность: 0.030.05
Статус: Участник

Создано: 18 декабря 2019 23:55 · Поправил: Ate
· Личное сообщение · #5

SDK пишет:
у них 1мс это максимум

В смысле минимум?

cppasm пишет:
открою тебе секрет

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

difexacaw пишет:
NtYieldExecution

Совершенно так же создаст нагрузку в цикле, аналогично цепочке

Code:
  1. Sleep() > SleepEx() > NtDelayExecution() > [KeGetPreviousMode() + KeDelayExecutionThread()] > Ki... (KiLockDispatcherDatabase, KiInsertTreeTimer, KiSetPriorityThread, KiFindReadyThread, KiReadyThread, KiInsertWaitList, KiComputeWaitInterval etc)
с нулевым аргументом.

Вообще
Code:
  1. LARGE_INTEGER  Interval;
  2. Interval.QuadPart = -(0.5 * 10000);
  3. NtDelayExecution(0, &Interval)


должно морозить на ~1/2 мс и решать задачу, но по факту идет задержка на полную миллисекунду.




Ранг: 568.2 (!), 465thx
Активность: 0.550.57
Статус: Участник
оптимист

Создано: 19 декабря 2019 00:23
· Личное сообщение · #6

Ate пишет:
есть ли альтернативный вызов не нагружающий CPU в подобном цикле?

создать отдельный поток?

-----
Чтобы правильно задать вопрос, нужно знать большую часть ответа. Р.Шекли.


| Сообщение посчитали полезным: difexacaw


Ранг: 338.5 (мудрец), 349thx
Активность: 2.112.42
Статус: Участник

Создано: 19 декабря 2019 00:30 · Поправил: difexacaw
· Личное сообщение · #7

Ate

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

Code:
  1.     // If no other threads are ready, then return immediately. Otherwise,
  2.     // attempt to yield execution.


Добавлено спустя 1 минуту
ClockMan

> создать отдельный поток?

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

-----
vx




Ранг: 54.0 (постоянный), 49thx
Активность: 0.721.1
Статус: Участник

Создано: 19 декабря 2019 00:31
· Личное сообщение · #8

Ate пишет:
минимум?
да ниже не падает



Ранг: 18.9 (новичок), 4thx
Активность: 0.030.05
Статус: Участник

Создано: 19 декабря 2019 01:13
· Личное сообщение · #9

ClockMan пишет:
создать отдельный поток?

Какая разница из какого потока проц грузить?

Уточню контекст. Есть цикл анимации:
Code:
  1. for (~100-200 итераций) {
  2. Animate();
  3. //Sleep(1);
  4. }

в таком виде время исполнения ~30мс, что слишком быстро,
если раскомментировать Sleep(1), исполняться будет ~200мс, что слишком медленно,
заменяем Sleep(1) альтернативным циклом, читающим по кругу InterruptTime, пока не пройдет нужное время, получаем 100мс, профит.

Суть вопроса касается этого самого внутреннего цикла. Это перманентное чтение и сравнение значений, туда не вставить паузы, поэтому он ест кпу как не в себя.
Я не знаю можно ли его реализовать иначе, но в какой трид его не сунь, нагрузка никуда не пропадет, так?

difexacaw пишет:
then return immediately

Я именно этот момент и подчеркул, что слип с нулем, что NtYield, прикинутся шлангами и их наличие, или отсутствие не повлияет никак.




Ранг: 568.2 (!), 465thx
Активность: 0.550.57
Статус: Участник
оптимист

Создано: 19 декабря 2019 01:28
· Личное сообщение · #10

Ate
пробуй через свой таймер CreateWaitableTimer,SetWaitableTimer,WaitForSingleObject

-----
Чтобы правильно задать вопрос, нужно знать большую часть ответа. Р.Шекли.




Ранг: 173.8 (ветеран), 208thx
Активность: 0.120.36
Статус: Участник

Создано: 19 декабря 2019 01:36
· Личное сообщение · #11

Хмм... без Sleep 30ms, с Sleep(1) 200ms...



Code:
  1. for ( i = *; ... i+=2 ) {
  2. Animate();
  3. Sleep(1);
  4. }


Если реализация позволяет увеличить шаг анимации, то это полностью решает проблему
Ваш КО

| Сообщение посчитали полезным: Ate


Ранг: 1053.6 (!!!!), 1078thx
Активность: 1.060.81
Статус: Участник

Создано: 19 декабря 2019 01:37
· Личное сообщение · #12

https://www.codeproject.com/Articles/1236/Timers-Tutorial



Ранг: 419.0 (мудрец), 647thx
Активность: 0.460.51
Статус: Участник
"Тибериумный реверсинг"

Создано: 19 декабря 2019 01:39
· Личное сообщение · #13

Ate пишет:
в таком виде время исполнения ~30мс, что слишком быстро,

Интреса ради, дистанцируясь от решения проблемы на уровне оси, если вызвать повторно Animate(); (или аналогичную ей процедуру без полезной нагрузки) и получить, условно ~60мс?

| Сообщение посчитали полезным: Ate

Ранг: 18.9 (новичок), 4thx
Активность: 0.030.05
Статус: Участник

Создано: 19 декабря 2019 01:59 · Поправил: Ate
· Личное сообщение · #14

ClockMan пишет:
пробуй через свой таймер CreateWaitableTimer

я в первом посте про него писал, не хочет он

ELF_7719116 пишет:
и получить, условно ~60мс?

Ну в принципе да, как-то так и выходит

VOLKOFF пишет:
это полностью решает проблему


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




Ранг: 605.2 (!), 341thx
Активность: 0.470.25
Статус: Модератор
Research & Development

Создано: 19 декабря 2019 02:50
· Личное сообщение · #15

Ate пишет:
Можно закрывать


Автор сам может закрыть свою тему, кнопка "Закрыть тему" находится внизу страницы, под кнопкой "Отправить сообщение".

-----
EnJoy!



 eXeL@B —› Программирование —› Вопрос по циклу
Эта тема закрыта. Ответы больше не принимаются.
   Для печати Для печати