Чтение онлайн

на главную - закладки

Жанры

Введение в QNX/Neutrino 2. Руководство по программированию приложений реального времени в QNX Realtime Platform

Кёртен Роб

Шрифт:

#define SEC_NSEC 1000000000LL // В одной секунде

// 1 биллион наносекунд

void* long_thread(void *notused) {

 printf("Этот поток выполняется более 10 секунд\n");

 sleep(20);

}

int main(void) // Игнорировать аргументы

{

 uint64_t timeout;

 struct sigevent event;

 int rval;

 pthread_t thread_id;

 //
Настроить событие — это достаточно сделать однажды

 // Либо так, либо event.sigev_notify = SIGEV_UNBLOCK:

 SIGEV_UNBLOCK_INIT(&event);

 // Создать поток

 pthread_create(&thread_id, NULL, long_thread, NULL);

 // Установить тайм-аут 10 секунд

 timeout = 10LL * SEC_NSEC;

 TimerTimeout(CLOCK_REALTIME, _NTO_TIMEOUT_JOIN, &event,

&timeout, NULL);

 rval = pthread_join(thread_id, NULL);

 if (rval == ETIMEDOUT) {

printf("Истекли 10 секунд, поток %d все еще"

" выполняется!\n",

thread_id);

 }

 sleep(5);

 TimerTimeout(СLOCK_REALTIME, _NTO_TIMEOUT_JOIN, &event,

&timeout, NULL);

 rval = pthread_join(thread_id, NULL);

 if (rval == ETIMEDOUT) {

printf("Истекли 25 секунд, поток %d все еще выполняется"

" (нехорошо)!\n",

thread_id);

 } else {

printf("Поток %d завершен (как и ожидалось!)\n",

thread_id);

 }

}

Мы применили макроопределение SIGEV_UNBLOCK_INIT для инициализации структуры события, но можно было установить sigev_notify в SIGEV_UNBLOCK и «вручную». Можно было даже сделать еще более изящно, передав NULL вместо

struct sigevent
— функция TimerTimeout понимает это как знак, что нужно использовать SIGEV_UNBLOCK.

Если поток (заданный в thread_id) остается работающим более 10 секунд, то системный вызов завершится по тайм-ауту — функция pthread_join возвратится с ошибкой, установив errno в ETIMEDOUT.

Вы можете использовать и другую «стенографию», указав NULL в качестве значения тайм-аута (параметр ntime в декларации выше), что предпишет ядру не блокироваться в данном состоянии. Этот прием можно использовать для организации программного опроса. (Хоть программный опрос и считается дурным тоном, его можно весьма эффективно использовать в случае с pthread_join, периодически проверяя, завершился ли нужный поток. Если нет, можно пока сделать что-нибудь другое.)

Ниже представлен пример программы, в которой демонстрируется неблокирующий вызов pthread_join:

int pthread_join_nb(int tid, void **rval) {

 TimerTimeout(CLOCK_REALTIME, _NTO_TIMEOUT_JOIN,

NULL, NULL, NULL);

 return (pthread_join(tid, rval));

}

Тайм-ауты
ядра при обмене сообщениями

Все становятся несколько сложнее, когда вы используете тайм-ауты ядра при обмене сообщениями. Вспомните главу «Обмен сообщениями», раздел «Обмен сообщениями и модель «клиент/сервер») — на момент отправки клиентом сообщения сервер может как ожидать его, так и нет. Это означает, что клиент может заблокироваться как по передаче (если сервер еще не принял сообщение), так и по ответу (если сервер принял сообщение, но еще не ответил). Основной смысл здесь в том, что вы должны предусмотреть оба блокирующих состояния в параметре flags функции TimerTimeout, потому что клиент может оказаться в любом из них.

Чтобы задать несколько состояний, сложите их операцией ИЛИ (OR):

TimerTimeout(... _NTO_TIMEOUT_SEND | _NTO_TIMEOUT_REPLY,

 ...);

Это вызовет тайм-аут всякий раз, когда ядро переведет клиента в состояние блокировки по передаче (SEND) или по ответу (REPLY). В тайм-ауте SEND-блокировки нет ничего особенного — сервер еще не принял сообщение, значит, ничего для этого клиента он не делает. Это значит, что если ядро генерирует тайм-аут для SEND-блокированного клиента, сервер об этом информировать не обязательно. Функция MsgSend клиента возвратит признак ETIMEDOUT и обработка тайм-аута завершится.

Однако, как было упомянуто в главе «Обмен сообщениями» (параграф «_NTO_CHF_UNBLOCK»), если сервер уже принял сообщение клиента, и клиент желает разблокироваться, для сервера существует два варианта реакции. Если сервер не указал флаг _NTO_CHF_UNBLOCK на канале, по которому было принято сообщение, клиент будет разблокирован немедленно, и сервер не получит об этом никакого оповещения. У большинства серверов, которые мне доводилось встречать, флаг _NTO_CHF_UNBLOCK был всегда установлен. В этом случае ядро посылает серверу импульс, а клиент остается заблокированным до тех пор, пока сервер ему не ответит! Как было показано в вышеупомянутом разделе главы «Обмен сообщениями», это сделано для того, чтобы сервер мог узнать о запросе клиента на разблокирование и выполнить по этому поводу какие-то действия.

Резюме

Мы рассмотрели функции QNX/Neutrino, ответственные за манипулирование временем, включая таймеры и их применение, а также тайм-ауты ядра. Относительные таймеры обеспечивают генерацию событий «через определенное число секунд», в то время как абсолютные таймеры генерируют события «в определенное время». Таймеры (и, вообще говоря, структура

struct sigevent
) могут обеспечить как выдачу импульса или сигнала, так и создание потока.

Ядро создает таймеры, сохраняя абсолютное время, представляющее последующее «событие», в отсортированной очереди и сравнивая текущее время (при помощи обработчика прерываний таймера) с значением, расположенным в голове этой очереди. Когда текущее время становится больше или равно времени, хранящемуся в головном элементе очереди, очередь просматривается на предмет дополнительных совпадений, после чего ядро диспетчеризует события или потоки (в зависимости типа элемента очереди) и, возможно, производит перепланирование.

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

Глава 4

Прерывания

QNX/Neutrino и прерывания

В данной главе мы рассмотрим прерывания, как с ними работать в QNX/Neutrino, их воздействие на диспетчеризацию и режим реального времени, а также некоторые стратегии их использования.

Поделиться:
Популярные книги

Газлайтер. Том 8

Володин Григорий
8. История Телепата
Фантастика:
попаданцы
альтернативная история
аниме
5.00
рейтинг книги
Газлайтер. Том 8

На Ларэде

Кронос Александр
3. Лэрн
Фантастика:
фэнтези
героическая фантастика
стимпанк
5.00
рейтинг книги
На Ларэде

Охота на попаданку. Бракованная жена

Герр Ольга
Любовные романы:
любовно-фантастические романы
5.60
рейтинг книги
Охота на попаданку. Бракованная жена

Кай из рода красных драконов

Бэд Кристиан
1. Красная кость
Фантастика:
попаданцы
альтернативная история
5.00
рейтинг книги
Кай из рода красных драконов

Хозяйка Проклятой Пустоши. Книга 2

Белецкая Наталья
2. Хозяйка Проклятой Пустоши
Любовные романы:
любовно-фантастические романы
5.00
рейтинг книги
Хозяйка Проклятой Пустоши. Книга 2

Безумный Макс. Поручик Империи

Ланцов Михаил Алексеевич
1. Безумный Макс
Фантастика:
героическая фантастика
альтернативная история
7.64
рейтинг книги
Безумный Макс. Поручик Империи

Потусторонний. Книга 2

Погуляй Юрий Александрович
2. Господин Артемьев
Фантастика:
фэнтези
попаданцы
аниме
5.00
рейтинг книги
Потусторонний. Книга 2

Чапаев и пустота

Пелевин Виктор Олегович
Проза:
современная проза
8.39
рейтинг книги
Чапаев и пустота

Солнечный корт

Сакавич Нора
4. Все ради игры
Фантастика:
зарубежная фантастика
5.00
рейтинг книги
Солнечный корт

Лютая

Шёпот Светлана Богдановна
Любовные романы:
любовно-фантастические романы
6.40
рейтинг книги
Лютая

Ведьмак (большой сборник)

Сапковский Анджей
Ведьмак
Фантастика:
фэнтези
9.29
рейтинг книги
Ведьмак (большой сборник)

Наследие Маозари 4

Панежин Евгений
4. Наследие Маозари
Фантастика:
фэнтези
попаданцы
5.00
рейтинг книги
Наследие Маозари 4

Ученик

Губарев Алексей
1. Тай Фун
Фантастика:
фэнтези
5.00
рейтинг книги
Ученик

Начальник милиции. Книга 5

Дамиров Рафаэль
5. Начальник милиции
Фантастика:
попаданцы
альтернативная история
5.00
рейтинг книги
Начальник милиции. Книга 5