LINUX.ORG.RU

Несколько таймеров из setitimer

 ,


0

3

Добрый день, ЛОР.

Понадобился мне таймер повышенной точности (кутешный в линуксе отрабатывает только с миллисекундной, в винде и того хуже, но винда меня сейчас, по счастью, не интересует). Смотрю в сторону setitimer().

Я правильно понимаю, что таймер типа ITIMER_REAL в программе можно создать только один? Никаких хэндлов и прочих идентификаторов эта функция не возвращает.

То есть, если таймеров нужно несколько, надо:

  • написать один обработчик SIGALRM;
  • вызвать setitimer(), в качестве периода брать НОД периодов нужных таймеров;
  • нужные субобработчики дёргать из него в зависимости от номера тика;
  • по окончании работы вызвать setitimer() с нулевым интервалом.

Или я что-то не понимаю / усложняю?

★★★★★

man

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

ITIMER_REAL
    уменьшается постоянно (в режиме реального времени) и подает сигнал SIGALRM, когда значение таймера становится равным 0. 
ITIMER_VIRTUAL
    уменьшается только во время работы процесса и подает сигнал SIGVTALRM, когда значение таймера становится равным 0. 
ITIMER_PROF
    уменьшается во время работы процесса и когда система выполняет что-либо по заданию процесса. Этот таймер обычно используется вместе с ITIMER_VIRTUAL для профилирования времени работы приложения в пользовательской области и в области ядра. Когда значение таймера становится равным 0, подается сигнал SIGPROF. 

Я бы предложил завести приоритетную очередь из которой тягать ближайшее срабатывание и извлекая значение ставить следующее. И ещё как резервный вариант поискал либо альтернативы, либо готовые высокоуровневые обёртки.

AKonia ★★ ()
Последнее исправление: AKonia (всего исправлений: 2)
Ответ на: комментарий от AKonia

И ещё как резервный вариант поискал либо альтернативы, либо готовые высокоуровневые обёртки.

Ну обёртки ладно, а какие альтернативы-то?

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

hobbit ★★★★★ ()
Последнее исправление: hobbit (всего исправлений: 1)
Ответ на: комментарий от hobbit

под альтернативами я грубо обобщил ситуации, когда в линуксе бывает, что соседствуют Linux и BSD api, дополнительные плюшки libc/glibc и пр., например posix timer_create у которого вроде для обработки сигнала можно через sigevent обработчик повесить, но там свои нюансы и нужно разбираться.

AKonia ★★ ()
Последнее исправление: AKonia (всего исправлений: 3)

Да, всё верно. Либо искать готовую библиотеку с оберткой либо писать свою. Например так

Pinkbyte ★★★★★ ()

Учти, что обработчик SIGALRM будет вызываться в рандомном контексте (в т.ч. может - в середине вычисления какой-нить однострочной формулы), в связи с чем из него нельзя много чего делать. В манах есть даже список (белый список) благонадёжных штук, которые там делать можно. В итоге обычно в обработчик сигнала ставят максимум установку какого-то флага в глобальной переменной типа «сигнал принят», а обрабатывают его уже в основном потоке исполнения программы. В связи с этим польза от этих таймеров сомнительная, ибо в основном потоке можно и самостоятельно всё это реализовать.

firkax ★★ ()
Ответ на: комментарий от firkax

Для того,чтобы этого не происходило делается отдельная нить, в которой делается while (flag) sleep(1), а во всех остальных нитях блокируется приход сигналов

PPP328 ★★★★ ()
Ответ на: комментарий от PPP328

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

firkax ★★ ()
Ответ на: комментарий от AKonia

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

Спасибо!

hobbit ★★★★★ ()
Ответ на: комментарий от hobbit

@hobbit, я еле жив.
Вы уж простите меня за критику вашу.
Конечно хотелось бы, что бы вера была у форумчан, но вера не у всех бывает.

Владимир

anonymous ()
Ответ на: комментарий от anonymous

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

Владимир

anonymous ()

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

pon4ik ★★★★★ ()

Никаких хэндлов и прочих идентификаторов эта функция не возвращает.

Возможно, ответ запоздал, но не подойдет ли Вам timerfd_create? Можно ждать сразу на нескольких таймерах в одном потоке, работает с привычным timespec (точнее, с аналогом для интервалов).

ghostmansd ()
Последнее исправление: ghostmansd (всего исправлений: 1)

Тебе точно нужна микросекундная точность? Я боюсь, что в дефолтном ядре это в принципе не гарантируется, а накладные расходы на выстрел прерывания и последующее перекладывание «события» в поток выполнения на корню загубит эту точность.

Если достаточно миллисекунд, то стандартное решение — встраивание таймаутов в основной цикл обработки событий (select/poll/etc) через приоритетную очередь таймеров.

filosofia ()
Ответ на: комментарий от hobbit

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

В мане есть строчка: «A process has only one of each of the three types of timers.»

i-rinat ★★★★★ ()
Ответ на: комментарий от filosofia

точно нужна микросекундная точность?

Очень хочу это хоть где-то увидеть. Серьёзные дядьки на серьёзном железе достигают 5мкс latency, а Вы о точности таймеров говорите. Ню-ню.

bugfixer ★★ ()
Последнее исправление: bugfixer (всего исправлений: 1)
Ответ на: комментарий от filosofia

Микросекундная точность мне не нужна, и я прекрасно знаю, что не получу её. А вот задавать период с большей точностью, чем миллисекунда — да, надо. Грубо говоря, событие должно происходить раз в 1,2 миллисекунды. Одна мало, две много. Соответственно, механизмы с миллисекундой в качестве единицы времени не подходят.

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

hobbit ★★★★★ ()
Ответ на: комментарий от hobbit

А вот задавать период с большей точностью, чем миллисекунда

Я не думаю что на стоковом ядре это реально. Разве что начинать изолировать ядра, прибивать гвоздями threads к ядрам и poll’ить.

А зачем это всё, если не секрет?

bugfixer ★★ ()
Ответ на: комментарий от bugfixer

Я не думаю что на стоковом ядре это реально.

Перефразирую: добиться avg wakeup freq в 1.2ms не так сложно в предположении что машинка idle most of the time, но jitter будет серьёзный.

bugfixer ★★ ()
Ответ на: комментарий от bugfixer

но jitter будет серьёзный

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

Спасибо.

hobbit ★★★★★ ()
Ответ на: комментарий от hobbit

Чтобы за несколько минут работы такого таймера не накопилось критичное расхождение.

Я не специалист по QT (UI в жизни не писал), но если там main event processing loop под Вашим контролем (или если QT позволяет schedule async events на произвольное время) то организовать само-коррекцию времени следующего wake up несложно, особенно учитывая насколько дёшев gettimeofday() нынче. Это то что бы я делал, возникни у меня такая необходимость.

ПыСы. А вот периодическим timers предоставляемым системой я бы не доверял ни под каким соусом, если drift важен.

bugfixer ★★ ()
Последнее исправление: bugfixer (всего исправлений: 2)
Для того чтобы оставить комментарий войдите или зарегистрируйтесь.