Установить таймаут для состояния блокировки
#include <time.h>extern int timer_timeout( clockid_t id,int flags,const struct sigevent *notify,const struct timespec *ntime,struct timespec *otime );extern int timer_timeout_r( clockid_t id,int flags,const struct sigevent *notify,const struct timespec *ntime,struct timespec *otime );
CLOCK_SOFTTIME
для сна, не "разбудит" процессор, когда приложение должно проснуться. Это позволит процессору перейти в режим энергосбережения. Когда процессор не находится в режиме энергосбережения таймеры типа CLOCK_SOFTTIME
аналогичны типу CLOCK_REALTIME
. NULL
, или указатель на структуру struct timespec, в которой функция сохранит оставшееся до срабатывания таймаута время.libc
Функции timer_timeout() и timer_timeout_r() идентичны, но по разному указывают на возникшие ошибки.
Функция timer_timeout() устанавливает таймаут из параметра ntime для любого состояния блокировки. Фактический таймаут будет сохранен в параметре otime. Для функций timer_timeout() и TimerTimeout() используется разрешение времени в наносекундах, но в этих функциях отличается формат задания времени. В функции timer_timeout() используется указатель на структуру struct timespec, содержащую 2 целочисленных значения, а в функции TimerTimeout() используется указатель на тип uint64_t
.
Время в параметре ntime функции TimerTimeout() также задается в наносекундах, но когда этот параметр передается в функцию TimerTimeout() время таймаута в структуре struct timespec формируется из секунд и наносекунд.
Состояния блокировки возникают в результате следующих системных вызовов:
STATE_INTR
STATE_RECEIVE
STATE_SEND
или STATE_REPLY
STATE_SIGSUSPEND
STATE_SIGWAITINFO
STATE_CONDVAR
STATE_MUTEX
STATE_SEM
STATE_JOIN
В программе задается, для каких состояний блокировки будет задан таймаут с помощью битовой маски в параметре flags. Нужные биты определены в следующих константах:
STATE_CONDVAR
. STATE_JOIN
. STATE_INTR
. STATE_MUTEX
. STATE_RECEIVE
. STATE_REPLY
. STATE_SEM
. STATE_SEND
. STATE_SIGSUSPEND
. STATE_SIGWAITINFO
. Например, чтобы установить таймаут для функции MsgSendv() необходимо задать:
_NTO_TIMEOUT_SEND | _NTO_TIMEOUT_REPLY
В случае, если таймаут задан функцией timer_timeout(), он будет включен или отключен при следующих условиях:
Функция timer_timeout() работает "одноразово". В случае, если блокируемый вызов ядра завершается (или прерывается сигналом), запрос на таймаут удаляется из системы. В потоке одновременно может сработать только один таймаут. Следующий вызов timer_timeout() заменит существующий таймаут в этом потоке. В случае, если значение параметра flags равно 0, таймаут не будет задан ни для какого состояния блокировки. Это значение используется по умолчанию при создании потока.
Функцию timer_timeout() необходимо вызывать непосредственно перед вызовом функции, для которой необходимо установить таймаут, например:
...event.sigev_notify = SIGEV_UNBLOCK;timeout.tv_sec = 10;timeout.tv_nsec = 0;timer_timeout( CLOCK_REALTIME, _NTO_TIMEOUT_SEND | _NTO_TIMEOUT_REPLY,&event, &timeout, NULL );MsgSendv( coid, NULL, 0, NULL, 0 );...
В случае, если между вызовами функций timer_timeout() и MsgSendv() будет вызван обработчик сигнала параметры функции timer_timeout() сохраняются во время обработки сигнала, а затем восстанавливаются при выходе из обработчика сигнала.
После срабатывания таймаута ядро посылает событие, указанное в параметре notify структуры struct sigevent. Рекомендуется использовать следующие типы событий:
Только при использовании типа SIGEV_UNBLOCK
гарантируется, то системный вызов будет разблокирован, поскольку сигнал может быть проигнорирован, заблокирован или принят другим потоком, а пульс может быть принят функцией MsgReceivev(). В случае, если параметр event равен NULL
, будет использоваться тип события SIGEV_UNBLOCK
. В данном случае при срабатывании таймаута блокируемый системный вызов завершится с ошибкой ETIMEDOUT
.
![]() | Функция MsgSendv() не разблокируется событием SIGEV_UNBLOCK , если сервер уже получил сообщение с помощью вызова MsgReceivev() и был установлен флаг _NTO_CHF_UNBLOCK при создании канала в функции ChannelCreate(). В этом случае сервер должен выполнить вызов MsgReplyv() или MsgError(). |
Особенности таймаута:
TIMER_ABSTIME
, при котором таймаут наступает в "абсолютное" время, определенное в ntime параметре.
1000000000
+ tv_nsec) / (значение системного тика) наносекунд.
<time.h>
).
![]() | В связи с особенностями измерения времени, таймер может фактически истечь позже указанного времени. |
В случае, если не требуется установить таймаут не определенное время, можно установить параметр ntime в NULL
. В этом случае не используется таймер и типом события является SIGEV_UNBLOCK
, а при входе в состояния блокировки, определенные флагами flags, функция сразу завершится с ошибкой ETIMEDOUT
. Такой подход можно использовать для приема (опроса) сообщений с помощью функции MsgReceivev(), которая будет сразу завершаться по таймауту. Более правильным вариантом является использование нескольких потоков с одним блокированном на приеме сообщений.
В случае, если в параметре flags установлено значение _NTO_TIMEOUT_NANOSLEEP
, тогда системные вызовы заблокируются в состоянии до срабатывания таймаута (или получения сигнала, который разблокирует поток). Такой подход может использоваться для реализации задержки следующим образом:
timer_timeout( CLOCK_REALTIME, _NTO_TIMEOUT_NANOSLEEP, NULL, &ntime, &otime );
В случае, если параметр otime не равен NULL
и задержка (sleep) будет разблокирована сигналом, то в этом параметре будет сохранено время, оставшееся до окончании задержки.
Данные вызовы является неблокируемыми, если в параметре flags не указано значение _NTO_TIMEOUT_NANOSLEEP
, иначе вызовы блокируются следующим образом:
-1
, код ошибки записывается в errno.
CLOCK_MONOTONIC
, CLOCK_SOFTTIME
, или CLOCK_REALTIME
. ЗОСРВ «Нейтрино»
Таймаут начинает отсчитываться от момента вызова функции timer_timeout(), а не при входе в состояние блокировки. Существует вероятность, что произойдет вытеснение потока после вызова timer_timeout() до перехода в состояние блокировки.
struct sigevent, struct timespec, TimerCreate(), TimerInfo(), TimerTimeout()
Предыдущий раздел: Описание API системной библиотеки