Медленные функции ожидания или select vc WaitFor...
От: Аноним  
Дата: 14.02.11 09:35
Оценка:
Добрый день всем!
Описание ситуации: использую overlapped file handlers для работы с COM-портами. Все работает, но все функции ожидания (SleepEx, WaitForSingle/MultipleObjectsEx) возвращают управление либо сразу (если к моменту их вызова ожидаемое событие уже свершилось-данные есть в приемном буфере или буфер отправки пуст), либо как минимум через 15 ms, даже если событие наступило раньше (скажем, через 2ms после вызова функции ожидания).
Собственно вопрос — можно ли уменьшить время простоя функции ожидания, т.е. чтоб она возвращала управление СРАЗУ ЖЕ по наступлению события (для примера выше — через 2 ms)? Либо использовать какой-либо другой механизм, скажем socket's select, которому на вход передавать файловые указатели на COM-порт (select для сокетов не имеет таких задержек)?
Re: Медленные функции ожидания или select vc WaitFor...
От: Jolly Roger  
Дата: 14.02.11 14:07
Оценка:
Здравствуйте, Аноним, Вы писали:

select работать вернее всего не будет и в любом случае ничего не даст. Эффект связан с особенностями работы планировщика и наличием других использующих процессор потоков. Попробуйте увеличить приоритет потока, который вызывает WaitForXXX
"Нормальные герои всегда идут в обход!"
Re: Медленные функции ожидания или select vc WaitFor...
От: Аноним  
Дата: 14.02.11 14:16
Оценка:
Здравствуйте, Аноним, Вы писали:

А>Либо использовать какой-либо другой механизм, скажем socket's select, которому на вход передавать файловые указатели на COM-порт (select для сокетов не имеет таких задержек)?


Может опрашивать через GetOverlappedResult с bWait == FALSE и ожидать активно?
Re[2]: Медленные функции ожидания или select vc WaitFor...
От: Аноним  
Дата: 14.02.11 17:33
Оценка:
Здравствуйте, Jolly Roger, Вы писали:

JR>select работать вернее всего не будет и в любом случае ничего не даст. Эффект связан с особенностями работы планировщика и наличием других использующих процессор потоков. Попробуйте увеличить приоритет потока, который вызывает WaitForXXX


Для сокетов select как раз дает эффект — возвращает по событию сразу, без задержки (просто если бы была задержка, то сеть под Windows работала бы очень медленно — попробуйте поставить после select:
Sleep(1);/*все равно будет задержка 16 ms */
и для интенсивного обмена — скорость сразу заметно упадет).

Я спросил по поводу сокетов потому, что обратный механизм т.е. ReadFileEx(socketHandle, ...) работает, вот я и предположил а вдруг работает и наоборот?

Подъем приоритета потока эффекта не дает.
Re[2]: Медленные функции ожидания или select vc WaitFor...
От: Аноним  
Дата: 14.02.11 17:38
Оценка:
А>Может опрашивать через GetOverlappedResult с bWait == FALSE и ожидать активно?

Не подходит — если спрашивать непрерывно, в цикле, то процессор отдаст все свое свободное время этому потоку ("100% загрузка" — это некрасиво). Если же сразу после опроса поставить даже минимальную задержку, Sleep(1); — будем снова получать задержку в 15 ms.
Re: Медленные функции ожидания или select vc WaitFor...
От: shasa  
Дата: 14.02.11 19:37
Оценка: +2
Здравствуйте, Аноним, Вы писали:
А>... скажем socket's select ...
Это всё реализовано через WaitForMultiplyObjects. Эти вызовы возвращают управление немедленно (при соотв. событии), там нет специальных, преднамеренных задержек. На длительность системных задержек ты повлиять не можешь. Если для твоей программы задержка системы критична — значит твоё решение не верно.
Re[3]: Медленные функции ожидания или select vc WaitFor...
От: Jolly Roger  
Дата: 15.02.11 03:45
Оценка: +1 -1
Здравствуйте, Аноним, Вы писали:

Когда поток ждёт объект ядра (event, нарпимер), он находится в состоянии Waiting. Когда объект переходит в сигнальное состояние, поток может быть переведён в состояние Running, Ready или Transition. В какое именно, зависит от текущего состояния системы, приоритета данного потока, а также приоритетов других активных потоков в системе. При этом только состояние Running означает немедленный доступ потока к процессору.

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

Windows не гарантирует какое-то детерменированное время реакции на события, а потому для построения систем реального времени она малопригодна, а при таких как у Вас требованиях к разрешению это вообще бесперспективно.
"Нормальные герои всегда идут в обход!"
Re[3]: Медленные функции ожидания или select vc WaitFor...
От: Jolly Roger  
Дата: 15.02.11 03:54
Оценка:
Здравствуйте, Аноним, Вы писали:

А как Вы измеряете эту задержку?
"Нормальные герои всегда идут в обход!"
Re[4]: Медленные функции ожидания или select vc WaitFor...
От: Аноним  
Дата: 15.02.11 07:42
Оценка:
Здравствуйте, Jolly Roger, Вы писали:

JR>А как Вы измеряете эту задержку?


При помощи GetTickCount() и __asm{...rdtsc...) это для x86 процессоров.
Re[4]: Медленные функции ожидания или select vc WaitFor...
От: Аноним  
Дата: 15.02.11 07:54
Оценка:
Здравствуйте, Jolly Roger, Вы писали:

JR>Величина задержки Sleep(1) определяется настройкой системного таймера. По умолчанию это примерно 10 или 15 миллисекунд (зависит, насколько я понимаю, от харда) и может быть измененена до минимум до 1-й миллисекунды.


Я согласен, НО sleep отмеряет в 99% случаев правильные интервалы — и в 1 и в 2 миллисекунды. Вот и есть желание воспользоваться его свойствами.

JR>Windows не гарантирует какое-то детерменированное время реакции на события, а потому для построения систем реального времени она малопригодна, а при таких как у Вас требованиях к разрешению это вообще бесперспективно.


Это так, но получается как-то обидно — на другом конце провода висит самый обычный 8-разрядный контроллер, который с этой задачей справляется в фоне, а на этом конце — ой. По моим текущим требованиям я "выдавил" из Windows нужные мне временные периоды, просто хотелось бы, по возможности, соптимизировать и иметь временной резерв.
Re[5]: Медленные функции ожидания или select vc WaitFor...
От: Jolly Roger  
Дата: 15.02.11 10:25
Оценка:
Здравствуйте, Аноним, Вы писали:

А>При помощи GetTickCount() и __asm{...rdtsc...) это для x86 процессоров


GetTickCount просто возвращает текущее значение системного счётчика, значения которого обновляется раз в те самые 10 или 15 миллисекунд, и способов это изменить нет. По крайней мере мне они не известны. Использовать GetTickCount для замера коротких интервалов нельзя. rdtsc связано с процессором, на многопроцессорных системах это необходимо учитывать.

А>Я согласен, НО sleep отмеряет в 99% случаев правильные интервалы — и в 1 и в 2 миллисекунды. Вот и есть желание воспользоваться его свойствами.


О каких 99% Вы говорите? sleep в 100% случаев даёт дискретность 10 или 15 мСек. По крайней мере, на всех системах NT-линейки, на которых мне это случалось проверить, оно так. Чтобы получить более высокое разрешение, необхолимо явно переконфигурировать таймер.

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

А>Это так, но получается как-то обидно — на другом конце провода висит самый обычный 8-разрядный контроллер, который с этой задачей справляется в фоне, а на этом конце — ой. По моим текущим требованиям я "выдавил" из Windows нужные мне временные периоды, просто хотелось бы, по возможности, соптимизировать и иметь временной резерв.


Странная какая-то обида Если система не подходит для данной задачи, значит надо или менять систему, или задачу, или способ её решения. На что или на кого тут обижаться?

А>По моим текущим требованиям я "выдавил" из Windows нужные мне временные периоды, просто хотелось бы, по возможности, соптимизировать и иметь временной резерв.


Ну дак оптимизируйте Просто ориентироваться надо на имеющиеся средства. А для этот надо хотя-бы примерно представлять, что они из себя представляют. Я-бы рекомендовал книгу Руссиновича и Соломона о внутреннем устройстве Windows.
"Нормальные герои всегда идут в обход!"
Re: Медленные функции ожидания или select vc WaitFor...
От: Mr. None Россия http://mrnone.blogspot.com
Дата: 15.02.11 10:48
Оценка:
Здравствуйте, Аноним, Вы писали:

А>Добрый день всем!

...
А>Собственно вопрос — можно ли уменьшить время простоя функции ожидания, т.е. чтоб она возвращала управление СРАЗУ ЖЕ по наступлению события (для примера выше — через 2 ms)? Либо использовать какой-либо другой механизм, скажем socket's select, которому на вход передавать файловые указатели на COM-порт (select для сокетов не имеет таких задержек)?

Для начала подучить матчасть. Это не функции ожидания медленные — это специфика работы у них такая.

1) Для выполнения ожидания эти функции переводят поток в режим ядра — уже одна эта операция весьма не быстрая и занимает в среднем около 1000 тактов процессора. Итого 1000 тактов в ядро + 1000 тактов обратно итого 2000 тактов (в случае гигагерцового процессора это примерно 2 микро-секунды).

2) После перехода в режим ядра, если событие ещё не случилось, поток теряет остаток процессорного кванта и ИСКЛЮЧАЕТСЯ ИЗ КАРУСЕЛИ ПЛАНИРОВАНИЯ. Эстафетная палочка переходит другому потоку. И пока он не отработает свой квант, ваш поток не имеет никаких шансов начать исполняться, если только приоритет вашего потока не выше. Размер кванта процессорного времени зависит от типа ОС. Для серверных ОС он одинаков для всех потоков и равен 16 ms. Для клиентских ОС он равен 12 ms для background процессов и увеличен для foreground процессов.

3) Даже если ожидаемое событие произошло в тот момент, когда текущий процесс закончил отрабатывать свой квант, скорее всего вы не получите управления, ибо ваш процесс будет всего лишь возвращён в карусель планировщика и помещён В САМЫЙ КОНЕЦ ОЧЕРЕДИ. Это означает, что прежде чем передать управление вам, свои кванты отработают как минимум ВСЕ процессы с тем же приоритетом, что и ваш, а как максимум и все процессы с большим приоритетом. Причём последние будут работать пока не заснут, каждый выталкивая процессы с меньшими приоритетами на задний план.

4) Передача управления другому процессу приводит к перелючению контекстов, эта операция примерно такая же "быстрая" что и переход в режим ядра. То есть добавляйте ещё n-ое количество тактов (сколько точно не знаю).

Вот и получается, что ну никак не можете вы получить управление через 2ms или повлиять на эту "задержку", как бы вы этого не хотели.

Если вам так критичны задержки в 15ms (что сравнимо с временем кванта, если вы могли заметить), то могу вам предложить ждать с помощью цикла. К примеру критическая секция так и делает: сначала некоторое количство времени ждёт с помощью цикла, чтобы не уходить в ядро зазря, а потом почестному засыпает на мьютексе.

Есть небольшой шанс улучшить ситуацию, установив приоритет вашего потока в максимальный: операционная система всегда отбирает квант у исполняющегося потока, если внезапно возникает желание поисполняться у потока, имеющего более высокий приоритет. Но опять таки не забывайте про задержки на переход между границами ядра и переключение контекстов. Ну и если в системе появится ещё один поток с таким же приоритетом что и ваш, то читайте пункт 3.
Компьютер сделает всё, что вы ему скажете, но это может сильно отличаться от того, что вы имели в виду.
Re[4]: Медленные функции ожидания или select vc WaitFor...
От: Mr. None Россия http://mrnone.blogspot.com
Дата: 15.02.11 10:58
Оценка:
Здравствуйте, Jolly Roger, Вы писали:

JR>Здравствуйте, Аноним, Вы писали:


...

JR>Величина задержки Sleep(1) определяется настройкой системного таймера. По умолчанию это примерно 10 или 15 миллисекунд (зависит, насколько я понимаю, от харда) и может быть измененена до минимум до 1-й миллисекунды.

...

Извините, но вы говорите неправду. Не нужно людей учить неправильному. Функция Sleep делает следующее: отбирает у потока остаток, кванта времени, убирает его из карусели планирования на время указанное в качестве аргумента. Когда время истекает, поток возвращается в конец очереди карусели планирования. Задержка в 15 милисекунд не связана ни с настройкой системного таймера, ни с положением звёзд на небе. Она связана лишь с размером кванта процессорного времени, выделяемого каждому потоку. Эта величина зависит только от одной вещи: опции "Processor scheduling". Которая доступна тут: My Computer / System Propertues / Advanced / Performance / Advanced. И Доступно вам всего 2 положения: делать как на серверах (16 милисекундный квант для всех) и как на клиентских машинах (12 милисекундный квант для фоновых задач и увеличненный до 30 милисекунд для задач на переднем плане). От ОС немного зависит алгоритм работы планировщика: дробить или нет квант на подкванты, способ увеличивания кванта для задач на переднем плане — дискретный или непрерывный и так далее, но величина в среднем остаётся неизменной примерно с NT 3.5.
Компьютер сделает всё, что вы ему скажете, но это может сильно отличаться от того, что вы имели в виду.
Re[5]: Медленные функции ожидания или select vc WaitFor...
От: Jolly Roger  
Дата: 15.02.11 11:59
Оценка:
Здравствуйте, Mr. None, Вы писали:

JR>>Величина задержки Sleep(1) определяется настройкой системного таймера. По умолчанию это примерно 10 или 15 миллисекунд (зависит, насколько я понимаю, от харда) и может быть измененена до минимум до 1-й миллисекунды.

MN>...

MN>Извините, но вы говорите неправду. Не нужно людей учить неправильному. Функция Sleep делает следующее: отбирает у потока остаток, кванта времени, убирает его из карусели планирования на время указанное в качестве аргумента. Когда время истекает, поток возвращается в конец очереди карусели планирования. Задержка в 15 милисекунд не связана ни с настройкой системного таймера, ни с положением звёзд на небе. Она связана лишь с размером кванта процессорного времени, выделяемого каждому потоку. Эта величина зависит только от одной вещи: опции "Processor scheduling". Которая доступна тут: My Computer / System Propertues / Advanced / Performance / Advanced. И Доступно вам всего 2 положения: делать как на серверах (16 милисекундный квант для всех) и как на клиентских машинах (12 милисекундный квант для фоновых задач и увеличненный до 30 милисекунд для задач на переднем плане). От ОС немного зависит алгоритм работы планировщика: дробить или нет квант на подкванты, способ увеличивания кванта для задач на переднем плане — дискретный или непрерывный и так далее, но величина в среднем остаётся неизменной примерно с NT 3.5.


Мои слова очень легко проверить с помощью примерно такого кода
timeEndPeriod(1);
Sleep(100);
QueryPerformanceCounter(&t1);
sleep(1);
QueryPerformanceCounter(&t2);
timeBeginPeriod(1);
Sleep(100);
QueryPerformanceCounter(&t3);
sleep(1);
QueryPerformanceCounter(&t4);
timeEndPeriod(1);

и сравнив (t2-t1) и (t4-t3).

По поводу звёзд ничего сказать не могу — не в курсе, потому Вам придётся самому как-то найти способ проверки.

Квант 12 мСек я лично не видел. Равный или кратный ~10 и ~15 видел, а 12 — нет

Всё остальное подробно расписано у того-же Соломона-Руссиновича, а переписывать всю книгу сюда целиком я не счёл возможным, извините
"Нормальные герои всегда идут в обход!"
Re[2]: Медленные функции ожидания или select vc WaitFor...
От: Jolly Roger  
Дата: 15.02.11 12:27
Оценка:
Здравствуйте, Mr. None, Вы писали:

MN> Размер кванта процессорного времени зависит от типа ОС. Для серверных ОС он одинаков для всех потоков и равен 16 ms. Для клиентских ОС он равен 12 ms для background процессов и увеличен для foreground процессов.


Я имел случай установить один и тот-же дистрибутив W2k Pro на две системы с разным хардом. При этом на одной было ~10 мСек, а на другой — 15 с мелочью. На текущей машине у меня стоит та-же W2k и WinXP Pro, две вполне себе клиентские машины. На обеих ~15,6 мСек.

MN>3) Даже если ожидаемое событие произошло в тот момент, когда текущий процесс закончил отрабатывать свой квант, скорее всего вы не получите управления, ибо ваш процесс будет всего лишь возвращён в карусель планировщика и помещён В САМЫЙ КОНЕЦ ОЧЕРЕДИ. Это означает, что прежде чем передать управление вам, свои кванты отработают как минимум ВСЕ процессы с тем же приоритетом, что и ваш, а как максимум и все процессы с большим приоритетом. Причём последние будут работать пока не заснут, каждый выталкивая процессы с меньшими приоритетами на задний план.


Единица планирования — поток. Процессы вообще не учавствуют в распределении процессорного времени, разве что их класс учитывается в вычислении приоритета потока.

MN>Если вам так критичны задержки в 15ms (что сравнимо с временем кванта, если вы могли заметить), то могу вам предложить ждать с помощью цикла. К примеру критическая секция так и делает: сначала некоторое количство времени ждёт с помощью цикла, чтобы не уходить в ядро зазря, а потом почестному засыпает на мьютексе.


Так делает крит. секция, если она инициализирована с помощью InitializeCriticalSectionAndSpinCount и только если код выполняется на многопроцессорной машине. "Не нужно людей учить неправильному"(c)
"Нормальные герои всегда идут в обход!"
Re[3]: Медленные функции ожидания или select vc WaitFor...
От: Jolly Roger  
Дата: 15.02.11 12:28
Оценка:
Здравствуйте, Jolly Roger, Вы писали:

JR>две вполне себе клиентские машины*


* — системы.
"Нормальные герои всегда идут в обход!"
Re[2]: Медленные функции ожидания или select vc WaitFor...
От: ononim  
Дата: 15.02.11 13:09
Оценка:
MN>2) После перехода в режим ядра, если событие ещё не случилось, поток теряет остаток процессорного кванта и ИСКЛЮЧАЕТСЯ ИЗ КАРУСЕЛИ ПЛАНИРОВАНИЯ. Эстафетная палочка переходит другому потоку. И пока он не отработает свой квант, ваш поток не имеет никаких шансов начать исполняться, если только приоритет вашего потока не выше.
Вообщето не только. Если другой поток переходит в режим ожидания переключение на ready поток из очереди происходит сразу же. Если вы единственный ready поток на этот момент времени вы сразу начнете работать
Как много веселых ребят, и все делают велосипед...
Re[3]: Медленные функции ожидания или select vc WaitFor...
От: Mr. None Россия http://mrnone.blogspot.com
Дата: 15.02.11 13:30
Оценка:
Здравствуйте, ononim, Вы писали:

MN>>2) После перехода в режим ядра, если событие ещё не случилось, поток теряет остаток процессорного кванта и ИСКЛЮЧАЕТСЯ ИЗ КАРУСЕЛИ ПЛАНИРОВАНИЯ. Эстафетная палочка переходит другому потоку. И пока он не отработает свой квант, ваш поток не имеет никаких шансов начать исполняться, если только приоритет вашего потока не выше.


O>Вообщето не только. Если другой поток переходит в режим ожидания переключение на ready поток из очереди происходит сразу же. Если вы единственный ready поток на этот момент времени вы сразу начнете работать


Из курса математики 1-ого курса мы помним, что над пустым множеством допустимы те же операции, что и над не пустым, поэтому имеем:
1) очередь планировщика пуста;
2) в её конец добавляется новый поток, вернувшийся из состояния ожидания, список потоков перед ним пуст;
3) он дожидается заверщения квантов времени для пустого списка потоков (то есть ждёт 0 секунд) и начинает исполняться...

Так что ваше утверждение логично следует из всего сказанного и не противоречит ему. Что вы имели в виду, я не понял.

Если уж на то пошло, то вариантов, когда поток лишается своего кванта времени масса:
1) он вызовет функцию SwitchToThread;
2) он запустит любую блокирующего (например, ввода-вывода или блокирующего чтения сообщения из очереди потока)

но это к делу отношения не имеет, поэтому предлагаю закрыть эту часть дискуссии — человек спрашивал совсем о другом.
Компьютер сделает всё, что вы ему скажете, но это может сильно отличаться от того, что вы имели в виду.
Re[4]: Медленные функции ожидания или select vc WaitFor...
От: ononim  
Дата: 15.02.11 13:35
Оценка:
MN>Так что ваше утверждение логично следует из всего сказанного и не противоречит ему. Что вы имели в виду, я не понял.
Ну значит я не понял что вы имеете ввиду, помедитируйте над особенностями русского языка, над тем что поток может перейти в wait не "выработав" до конца отпущенный ему квант времени и слудеющей из этого многозначностью выражения "пока он не отработает свой квант"
Как много веселых ребят, и все делают велосипед...
Re: Медленные функции ожидания или select vc WaitFor...
От: Аноним  
Дата: 15.02.11 13:51
Оценка:
Здравствуйте, Аноним, Вы писали:

timeBeginPeriod? как возможный эффект — нагрузка на цпу и временные траблы
Подождите ...
Wait...
Пока на собственное сообщение не было ответов, его можно удалить.