Введение в QNX/Neutrino 2. Руководство по программированию приложений реального времени в QNX Realtime Platform
Шрифт:
Типы
Таймер, работу которого мы только что обсудили, называют относительным таймером. Для такого таймера период ожидания задается относительно текущего времени. Если бы вы пожелали задержать выполнение вашего потока до 12 часов 4 минут 33 секунд EDT (Eastern Daylight Time — восточное поясное время — прим. ред.) 20 января 2005 года, вам пришлось бы сначала рассчитать точное число секунд от «сейчас» до выбранного вами момента и включить относительный таймер с задержкой на это число секунд. Поскольку это довольно часто встречающаяся операция, в QNX/Neutrino реализованы абсолютные таймеры, которые обеспечивают задержку до заданного времени (а не на заданное время, как в случае относительного таймера).
А что если вы захотите сделать что-нибудь полезное, пока поток ожидает наступления установленной даты? Или делать что-либо и получать «синхроимпульс» каждые 27 секунд? Здесь нельзя просто так позволить себе спать!
Как мы уже обсуждали в главе «Процессы и потоки», вы можете просто запустить другой поток, и пусть он выполняет работу, пока ваш поток спит. Однако, поскольку мы говорим сейчас о таймерах, посмотрим, как это можно сделать другим способом.
В зависимости от выбранной цели, вы можете сделать это с помощью либо периодического, либо однократного таймера. Периодический таймер — это таймер, который срабатывает периодически, уведомляя поток (снова и снова), что истек некоторый временной интервал. Однократный таймер — это таймер, который срабатывает только один раз.
Реализация этих таймеров в ядре основана на том же самом принципе, что и в случае с таймером задержки из нашего первого примера. Ядро запоминает абсолютное значение времени (если вы укажете сделать именно так) и хранит его. Обработчик прерываний таймера сравнивает сохраненное значение времени с текущим.
Однако, вместо удаления из очереди на выполнение после системного вызова, на этот раз ваш поток продолжит работу. И в момент, когда суточное время достигнет заданного вами и хранимого в памяти момента времени, ядро уведомит ваш поток о том, что назначенное время пришло.
Схема уведомления
Как получить уведомление о тайм-ауте? При использовании таймера задержки вы получаете уведомление просто посредством возвращения в состояние READY.
При использовании периодически и однократных таймеров у вас появляется выбор:
• послать импульс;
• послать сигнал:
• создать поток.
Импульсы мы уже обсуждали главе «Обмен сообщениями»; сигналы — стандартный для UNIX механизм. Здесь же мы кратко рассмотрим уведомления при помощи создания потока.
Независимо от выбранной вами схемы уведомления, вам обязательно придется заполнять структуру
Первое поле, которое вы должны заполнить, — это элемент sigev_notify, который определяет выбранный вами тип уведомления:
SIGEV_PULSE
Будет передан импульс.
SIGEV_SIGNAL, SIGEV_ SIGNAL _CODE или SIGEV_SIGNAL_THREAD
Будет передан сигнал.
SIGEV_UNBLOCK
В данном случае не используется; предназначен для тайм-аутов ядра (см. ниже в разделе «Тайм-ауты ядра»).
SIGEV_INTR
В данном случае не используется; предназначен для прерываний (см. главу «Прерывания»),
SIGEV_THREAD
Будет создан поток.
Поскольку мы намерены использовать структуру
Чтобы передать импульс при срабатывании таймера, присвойте полю sigev_notify значение SIGEV_PULSE и обеспечьте немного дополнительной информации:
Поле | Значение и смысл |
---|---|
sigev_coid | Идентификатор соединения (connection ID), по каналу которого которому будет передан импульс. |
sigev_value | 32-разрядное значение (данные импульса — см. параграф «Что внутри импульса?», глава «Обмен сообщениями» — прим. ред.), которое будет передано по заданному полем sigev_coid соединению. |
sigev_code | 8-разрядное значение (код импульса — см. параграф «Что внутри импульса?», глава «Обмен сообщениями» — прим. ред.), которое будет передано по заданному полем sigev_coid соединению. |
sigev_priority | Приоритет доставки импульса. Нулевое значение не допускается — слишком уж много людей пострадало от переключения на нулевой приоритет после получения импульса, а поскольку на этом приоритете приходится конкурировать за процессор со спецпроцессом IDLE, много процессорного времени там точно не светит :-). |