URL: https://www.opennet.me/cgi-bin/openforum/vsluhboard.cgi
Форум: vsluhforumID9
Нить номер: 9642
[ Назад ]

Исходное сообщение
"переключение задачи до завершения временного кванта"

Отправлено Нестор , 24-Фев-13 22:54 
Задача: отслеживается событие и при его возникновении обрабатывается.
Решение:
while (1) {
    if ( <событие> ) {
        <обработка>
    }
}
Проблема: много холостых ходов цикла, загрузка процессора до 100%

В Windows решается просто:
while (1) {
    if ( <событие> ) {
        <обработка>
        continue;
    }
    else {
        Sleep (0);
    }
}
здесь функция Sleep(0) позволяет планировщику передать исполнение другому потоку до истечения кванта времени выделенного текущему потоку.

Вопрос: Как подобный механизм реализовать в UNIX ?


Содержание

Сообщения в этом обсуждении
"переключение задачи до завершения временного кванта"
Отправлено elvenic , 25-Фев-13 02:55 
> Решение:
> while (1) {
>  if ( <событие> ) {
>   <обработка>
>  }
> }
> Проблема: много холостых ходов цикла, загрузка процессора до 100%

Решение не совсем правильное. (Я, кстати, очень сильно удивлюсь если в Виндовсе при использовании Sleep() загрузка процессора будет не 100%).

Правильно - использовать select() (man 2 select) или poll() (man 2 poll), что-то типа

while (select(...)) {
  // event happened. Process it:
  ...
}

при этом внутри цикла нет ветки else со sleep() - select() сам ждет события, и поскольку он реализован через системный вызов, кернел знает что данный поток будет не активным пока не произойдет событие заданное параметрами select()'а, и может наиболее эффективно распорядится ресурсами системы - например, поток не будет активизирован просто чтобы убедится что событие еще не наступило и сказать sleep() в очередной раз.

select()/poll() работают ожидая события ввода/вывода на файловых дескрипторах (наличия данных для чтения, готовности к записи, возникновения ошибки), но это на самом деле не является существенным ограничением:

а) если событие которого вы ждете это событие ввода/вывода на файловом дескрипторе к которому вы имеете доступ, оно прямо транслируется в параметеры select()/poll();

б) если это какое-то иное событие, значит где-то в системе есть поток который висит на вызове функции, завершение которой и будет сигналом этого события (напр. ожидание завершения вызова функции интерфейса какой-то базы данных, или ожидание ответа от пользователя в потоке графического интерфейса, и т.д). В этом случае довольно легко организовать пару файловых дескрипторов (напр. функцией pipe() (man pipe)); поток который ожидает события в цикле while(select()) на самом деле ожидает наличия данных на выходном конце pipe'а, а поток который дождался завершения вызова функции, поставляет эти данные - пишет, например, всего 1 байт во входной конец pipe'а, после чего select() в другом потоке завершается и тело цикла while выполняется.

А кстати, man sched_yield чтобы почитать о функции которая отдает квант выделеный текущему потоку, хотя по-моему это не то что тут требуется.


"переключение задачи до завершения временного кванта"
Отправлено pavlinux , 25-Фев-13 03:16 
> которая отдает квант выделенный текущему потоку

Ничё она не отдаёт, а говорит планировщику "елси нада, то могёшь меня переместить в конец очереди".
Более того, поведение родственных нитей зависит от типа приоритета: OTHER, BATCH, IDLE, FIFO, RR, DEADLINE;
C FIFOй мож ваще не переключится, а тормознёт, планировщик увидит, что у тя самый большой приоритет и вернёт
обратно на первое место к процессору.


"переключение задачи до завершения временного кванта"
Отправлено pavlinux , 25-Фев-13 03:12 
> Вопрос: Как подобный механизм реализовать в UNIX ?

sched_yield()

---
И ваще, планировщики и проблемы разруливания процессов/нитей - это задачи
системного программирования, а не прикладного.


"переключение задачи до завершения временного кванта"
Отправлено Andrey Mitrofanov , 25-Фев-13 09:27 
> И ваще, планировщики и проблемы разруливания процессов/нитей - это задачи
> системного программирования, а не прикладного.

Точно. Именно в этом уверены все :)прикладники.


"переключение задачи до завершения временного кванта"
Отправлено Нестор , 28-Фев-13 09:14 
Спасибо за ответы. Я действительно немного промахнулся с темой, поищу в теме про потоки и нити.

К сожалению sched_yield() не помогает в данном случае, например:

   void main () {
      while (1) {
      }
   }

и

   void main () {
      while (1) {
         sched_yield ();
      }
   }

согласно top дают одинаковую загрузку CPU ~100%

Однако

   void main () {
      while (1) {
         usleep (1000);
      }
   }

резко уменьшает нагрузку до 0.3%

Наверное это и есть решение.


"переключение задачи до завершения временного кванта"
Отправлено Mr. Mistoffelees , 28-Фев-13 13:41 
Привет,

>  if ( <событие> ) {
>   <обработка>
>  }

Ответ зависит от того, в чем заключается обработка и точнее, насколько она должна быть в реальном времени. Лучший вариант, конечно, select() - есил есть возможность его использовать. usleep() позволит снизить нагрузку, а интервал зависит от того, как часто случается событие и насколько его обработка может подождать - напр., если "событие", это уборка за каким-то "мусором" (типа wait() после fork()), то и раз в секунду подойдет.

WWell,



"переключение задачи до завершения временного кванта"
Отправлено Нестор , 28-Фев-13 14:26 
>[оверквотинг удален]
>>  if ( <событие> ) {
>>   <обработка>
>>  }
> Ответ зависит от того, в чем заключается обработка и точнее, насколько она
> должна быть в реальном времени. Лучший вариант, конечно, select() - есил
> есть возможность его использовать. usleep() позволит снизить нагрузку, а интервал зависит
> от того, как часто случается событие и насколько его обработка может
> подождать - напр., если "событие", это уборка за каким-то "мусором" (типа
> wait() после fork()), то и раз в секунду подойдет.
> WWell,

Доброго времени суток!

Реальная задача в получении пакетов на неблокированные сокеты:

   while (1) {
      . . .
      if ( !poll(. . .) ) {
         continue;
      }

      <обработка>

   }

select() не пробовал, но использование poll(), как в приведённом примере, оставляет загрузку CPU ~100%.


"переключение задачи до завершения временного кванта"
Отправлено Mr. Mistoffelees , 13-Мрт-13 14:36 
Привет,

> Реальная задача в получении пакетов на неблокированные сокеты:
> select() не пробовал, но использование poll(), как в приведённом примере, оставляет загрузку
> CPU ~100%.

Тогда попробуйте select(), он и есть ваше решение.

WWell,



"переключение задачи до завершения временного кванта"
Отправлено Аноним , 01-Апр-13 14:54 
> select() не пробовал, но использование poll(), как в приведённом примере, оставляет загрузку
> CPU ~100%.

Если загрузка 100%, то timeout=0. Ну уж тогда извините, что написали - то и получили.
select() не поможет, так как на уровне ядра всё равно реализован через poll().


"переключение задачи до завершения временного кванта"
Отправлено nanoo_linux , 12-Мрт-13 20:05 
>[оверквотинг удален]
>   <обработка>
>   continue;
>  }
>  else {
>   Sleep (0);
>  }
> }
> здесь функция Sleep(0) позволяет планировщику передать исполнение другому потоку до истечения
> кванта времени выделенного текущему потоку.
> Вопрос: Как подобный механизм реализовать в UNIX ?

То что ты делаешь называется опрос. И это именно то, чего делать не стоит. Для этого алгоритма избежать 100% загрузки цпу невозможно. Вариант с usleep - костыль, который резко уменьшает время ответа системы.

Само получение ивента должно быть блокируемым. Самое простое решение - завести дескриптор при помощи man 2 pipe и с одной стороны - писать, а с другой - читать в блокирующем режиме ивенты.


"переключение задачи до завершения временного кванта"
Отправлено anonymous , 15-Мрт-13 21:07 
>[оверквотинг удален]
>> }
>> здесь функция Sleep(0) позволяет планировщику передать исполнение другому потоку до истечения
>> кванта времени выделенного текущему потоку.
>> Вопрос: Как подобный механизм реализовать в UNIX ?
> То что ты делаешь называется опрос. И это именно то, чего делать
> не стоит. Для этого алгоритма избежать 100% загрузки цпу невозможно. Вариант
> с usleep - костыль, который резко уменьшает время ответа системы.
> Само получение ивента должно быть блокируемым. Самое простое решение - завести дескриптор
> при помощи man 2 pipe и с одной стороны - писать,
> а с другой - читать в блокирующем режиме ивенты.

Зря, что ли, придумывали асинхронно-событийную парадигму?


"переключение задачи до завершения временного кванта"
Отправлено pavlinux , 16-Мрт-13 22:17 
> Зря, что ли, придумывали асинхронно-событийную парадигму?

А не из теории что-нибудь?!



"переключение задачи до завершения временного кванта"
Отправлено anonymous , 17-Мрт-13 22:02 
>> Зря, что ли, придумывали асинхронно-событийную парадигму?
> А не из теории что-нибудь?!

http://libevent.org/ || http://software.schmorp.de/pkg/libev.html