Роб Кёртен - Введение в QNX/Neutrino 2. Руководство по программированию приложений реального времени в QNX Realtime Platform
- Название:Введение в QNX/Neutrino 2. Руководство по программированию приложений реального времени в QNX Realtime Platform
- Автор:
- Жанр:
- Издательство:Петрополис
- Год:2001
- Город:Санкт-Петербург
- ISBN:5-94656-025-9
- Рейтинг:
- Избранное:Добавить в избранное
-
Отзывы:
-
Ваша оценка:
Роб Кёртен - Введение в QNX/Neutrino 2. Руководство по программированию приложений реального времени в QNX Realtime Platform краткое содержание
Книга "Введение в QNX/Neutrino 2» откроет перед вами в мельчайших подробностях все секреты ОСРВ нового поколения от компании QNX Software Systems Ltd (QSSL) — QNX/Neutrino 2. Книга написана в непринужденной манере, легким для чтения и понимания стилем, и поможет любому, от начинающих программистов до опытных системотехников, получить необходимые начальные знания для проектирования надежных систем реального времени, от встраиваемых управляющих приложений до распределенных сетевых вычислительных систем
В книге подробно описаны основные составляющие ОС QNX/Neutrino и их взаимосвязи. В частности, уделено особое внимание следующим темам:
• обмен сообщениями: принципы функционирования и основы применения;
• процессы и потоки: базовые концепции, предостережения и рекомендации;
• таймеры: организация периодических событий в программах;
• администраторы ресурсов: все, что относится к программированию драйверов устройств;
• прерывания: рекомендации по эффективной обработке.
В книге представлено множество проверенных примеров кода, подробных разъяснений и рисунков, которые помогут вам детально вникнуть в и излагаемый материал. Примеры кода и обновления к ним также можно найти на веб-сайте автора данной книги, www.parse.com.
Введение в QNX/Neutrino 2. Руководство по программированию приложений реального времени в QNX Realtime Platform - читать онлайн бесплатно полную версию (весь текст целиком)
Интервал:
Закладка:
// Обработать его
} else { // Это обычное сообщение
// Определить тип сообщения
// Обработать его
}
Итак, вы принимаете сообщение с нулевым идентификатором отправителя. Что у него внутри? Вот фрагмент заголовочного файла :
struct _pulse {
_uint16 type;
_uint16 subtype;
_int8 code;
_uint8 zero[3];
union sigval value;
_int32 scoid;
};
Элементы type и subtype равны нулю (это еще один признак того, что перед нами импульс); содержимое элементов code и value определяется отправителем. В общем случае элемент code будет указывать на причину, по которой был отправлен импульс, а параметр value будет содержать 32 бита данных, ассоциируемых с данным импульсом. Эти два поля и есть те самые 40 бит контента; другие поля пользователем не настраиваются.
Ядро резервирует отрицательные значения параметра code , оставляя 127 значений для программистов — для использования по своему усмотрению.
Элемент value в действительности является элементом типа union
:
union sigval {
int sival_int;
void *sival_ptr;
};
Поэтому (в развитие примера с сервером, представленного выше) вы часто будете видеть программу, подобную этой:
#include
rcvid = MsgReceive(chid, ...
if (rcvid == 0) { // Импульс
// Определить тип импульса
switch (msg.pulse.code) {
case MY_PULSE_TIMER:
// Сработал один из наших таймеров,
// надо что-то делать...
break;
case MY_PULSE_HWINT:
// Импульс получен от обработчика прерывания.
// Надо заглянуть в поле «value»...
val = msg.pulse.value.sival_int;
// Сделать что-нибудь по этому поводу...
break;
case _PULSE_CODE_UNBLOCK:
// Это импульс от ядра, разблокирующий клиента
// Сделать что-нибудь по этому поводу...
break;
//и так далее...
}
} else { // Обычное сообщение
// Определить тип сообщения
// Обработать его
}
В этой программе предполагается, конечно, что вы описали структуру msg так, чтобы она содержала элемент « struct _pulse pulse;
», и что определены константы MY_PULSE_TIMER и MY_PULSE_HWINT. Код импульса _PULSE_CODE_UNBLOCK — один из тех самых отрицательных кодов, зарезервированных для ядра, как это было упомянуто выше. Вы можете найти полный список этих кодов (а также краткое описание поля value ) в .
Функции MsgReceive() и MsgReceivev() могут принимать либо стандартное сообщение, либо импульс. Однако, возможны ситуации, когда вы пожелаете принимать только импульсы. Лучшим примером этого является ситуация с сервером, когда вы приняли запрос от клиента на выполнение чего-нибудь, но не можете выполнить этот запрос сразу (возможно, из-за длительной операции, связанной с аппаратными средствами). В таких случаях следует, как правило, настроить аппаратные средства (или таймер, или что-нибудь еще) на передачу вам импульса всякий раз, когда происходит некое значительное событие.
Если вы напишете ваш сервер по стандартной схеме «ждать сообщения в бесконечном цикле», вы можете оказаться в ситуации, когда один клиент посылает вам запрос, а потом, пока вы ожидаете импульса, который должен сигнализировать об отработке запроса, приходит запрос от другого клиента. Вообще говоря, это как раз то что нужно — в конце концов, мы хотели иметь способность одновременно обслуживать множество клиентов. Однако, у вас могут быть веские основания отказать клиенту в обслуживании — например, если обслуживание клиента слишком ресурсоемко, и надо ограничить численность одновременно обрабатываемой клиентуры.
В таком случае вам потребуется обеспечить возможность «выборочного» приема только импульсов. Тут-то и становится актуальной функция MsgReceivePulse() :
#include
int MsgReceivePulse(int chid, void *rmsg, int rbytes,
struct _msg_info *info);
Видно, что ее параметры те же, что и у функции MsgReceive() — идентификатор канала, буфер (и его размер), и параметр info — мы обсуждали его в параграфе «Кто послал сообщение?» Заметьте, что параметр info не применяется в импульсах. Вы можете спросить, почему он представлен в списке параметров. Ответ незамысловат: так было проще сделать. Просто передайте NULL!
Функция MgsReceivePulse() способна принимать только импульсы. Так, если бы у вас был канал с множеством потоков, блокированных на нем с помощью функции MsgReceivePulse() (и ни одного потока, блокированного на нем с помощью функции MsgReceive() ), и некий клиент попытался бы отправить вашему серверу сообщение, то этот клиент остался бы заблокированным по передаче (Send-blocked) до тех пор, пока какой-либо поток сервера не вызовет MsgReceive() . Тем временем функция MsgReceivePulse() будет спокойно принимать импульсы.
Единственное, что можно гарантировать при совместном применении функций MsgReceivePulse() и MsgReceive() , — что функция MsgReceivePulse() обеспечит прием исключительно импульсов. Функция MsgReceive() сможет принимать как импульсы, так и обычные сообщения! Это происходит потому, что применение функции MsgReceivePulse() зарезервировано специально для случаев, где нужно исключить получение сервером обычных сообщений.
Это немного вводит в замешательство. Так как функция MsgReceive() может принимать и обычные сообщения, и импульсы, а функция MsgReceivePulse() может принимать только импульсы, то как быть с сервером, в котором применяются обе функции? Общий ответ такой. У вас есть пул потоков, выполняющих MsgReceive() . Этот пул потоков (один или более потоков — это зависит от числа клиентов, которое вы хотели бы обслуживать одновременно) отвечает за обработку запросов от клиентов.
Поскольку вы пытаетесь управлять численностью потоков- обработчиков, и некоторым из этих потоков может понадобиться блокироваться в ожидании импульса (например, от оборудования или от другого потока), вы блокируете поток-обработчик при помощи функции MsgReceivePulse() . Функция MsgReceivePulse() принимает только импульсы, а значит, ее применение гарантирует, что пока вы ждете импульса, к вам ненароком не просочится никакой клиентский запрос.
Функция MsgDeliverEvent()
Как было упомянуто выше в параграфе «Иерархический принцип обмена», существуют ситуации, когда приходится нарушать естественное направление передач.
Такой случай возможен, когда у вас есть клиент, который посылает серверу сообщение и при этом не хочет блокироваться, а результат может быть доступен только через некоторое время. Конечно, вы могли бы частично решить эту проблему путем применения многопоточных клиентов, выделяя в клиенте отдельный поток для блокирующих вызовов сервера, но это не всегда с успехом работает в больших системах, поскольку при большом количестве серверов количество ждущих потоков было бы слишком велико. Но допустим, вы не хотите здесь использовать многопоточность, а вместо этого вам нужно, чтобы сервер ответил клиенту сразу, и чем-то вроде «Заказ принят; я скоро вернусь». Здесь, поскольку сервер ответил, клиент теперь свободен продолжать свою работу. После того как сервер отработает запрос клиента, ему потребуется как-то сказать клиенту «Проснись, вот твой заказ.» Очевидно, как мы это уже видели при анализе иерархического принципа обмена, сервер не должен передавать сообщения клиенту, потому что если клиент в это же время отправит сообщение серверу, это может вызывать взаимную блокировку. Так как же сервер может послать сообщение клиенту без нарушения иерархического принципа?
Читать дальшеИнтервал:
Закладка: