Роб Кёртен - Введение в 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 - читать онлайн бесплатно полную версию (весь текст целиком)
Интервал:
Закладка:
2. Использовать для объявления идентификаторов ND/PID/CHID глобальные переменные. Такой способ обычно применяется в многопоточных серверах, которые могут посылать сообщение сами себе. Этот вариант по самой своей природе является очень редким.
3. Занять часть пространства имен путей и стать администратором ресурсов. Мы поговорим об этом в главе «Администраторы ресурсов».
Первый подход относительно прост, но он чреват «загрязнением файловой системы», когда в каталоге /etc
лежит куча файлов *.pid
. Поскольку файлы устойчивы (имеется в виду, что они выживают после смерти создающего их процесса и перезагрузки машины), очевидного способа стереть эти файлы не существует — разве что использовать этакую программную «старуху с косой», постоянно проверяющую, не пора ли прибрать кого-то из них.
Имеется и другая связанная с этим подходом проблема. Поскольку процесс, который создал файл, может умереть, не удалив этот файл, то вы не сможете узнать, жив ли еще этот процесс, пока не попробуете передать ему сообщение. И это ещё не самое страшное — еще хуже, если комбинация ND/PID/CHID указанная в файле, оказывается настолько старой, что может быть повторно использована другой программой! Получив «чужое» сообщение, эта программа в лучшем случае его проигнорирует его, а ведь может и предпринять некорректные действия. Так что такой подход исключается.
Второй подход, где мы используем глобальные переменные для объявления значений ND/PID/CHID, не является общим решением проблемы, поскольку в нем предполагается способность клиента обратиться к этим глобальным переменным. А поскольку для этого требуется использование разделяемой памяти, это не будет работать в сети! Так что этот метод обычно используется либо в небольших тестовых программах, либо в очень специфичных случаях, но всегда в контексте многопоточной программы.
Что реально происходит, так это то, что один поток в программе является клиентом, а другой поток — сервером. Поток-сервер создает канал и затем размещает идентификатор канала в глобальной переменной (идентификаторы узла и процесса являются одинаковыми для всех потоков в процессе, так что объявлять их не обязательно). Поток-клиент затем берет этот идентификатор канала и выполняет по нему функцию ConnectAttach() .
Третий подход — сделать сервер администратором ресурса — является определенно самым прозрачным и поэтому рекомендуемым общим решением. Механизм того, как это делается, изложен в главе «Администраторы ресурсов», а пока все, что вы должны об этом знать — это то, что сервер регистрирует некое имя пути как свою «область ответственности», а клиенты обращаются к нему обычным вызовом функции open() .
Не сочту лишним подчеркнуть:
Файловые дескрипторы POSIX в QNX/Neutrino реализованы через идентификаторы соединений, то есть дескриптор файла уже является идентификатором соединения! Органичность этой схемы в том, что поскольку дескриптор файла, возвращаемый функцией open() , фактически является идентификатором соединения, клиенту не нужно выполнять какие-либо дополнительные действия, чтобы использовать это соединение. Например, когда клиент после вызова open() вызывает функцию read() , передавая ей полученный дескриптор, это с минимальными накладными расходами транслируется в функцию MsgSend() .
А что произойдет, если сообщение серверу передадут одновременно два процесса с разными приоритетами?
Сообщения всегда доставляются в порядке приоритетов.
Если два процесса посылают сообщения «одновременно», первым доставляется сообщение от процесса с высшим приоритетом.
Если оба процесса имеют одинаковый приоритет, то сообщения будут доставлены в порядке отправки (поскольку в машине с одним процессором не бывает ничего одновременного, и даже в SMP-блоке будет присутствовать некий порядок, поскольку процессоры будут конкурировать между собой за доступ к ядру).
Мы еще вернемся к анализу других тонкостей этой проблемы чуть позже в этой главе, когда будем говорить о проблеме инверсии приоритетов.
До настоящего времени мы обсуждали основные примитивы обмена сообщениями. Как я и упоминал ранее, это минимум, который необходимо знать. Однако существует еще несколько дополнительных функций, которые делают нашу жизнь значительно проще.
Рассмотрим пример, в котором для обеспечения обмена сообщениями между клиентом и сервером нам понадобились бы и другие функции.
Клиент вызывает MsgSend() для передачи неких данных серверу. После вызова MsgSend() клиент блокируется. Теперь он ждет, чтобы сервер ему ответил.
Интересные события разворачиваются на стороне сервера. Сервер вызывает функцию MsgReceive() для приема сообщения от клиента. В зависимости от того, как вы спроектировали вашу систему сообщений, сервер может знать, а может и не знать, насколько велико сообщение клиента. Как сервер может не знать, каков реальный размер сообщения? Возьмем наш пример с файловой системой. Предположим, что клиент делает так:
write(fd, buf, 16);
Это сработает так, как и ожидается, если сервер вызовет MsgReceive() с размером буфера, скажем, 1024 байта. Так как наш клиент послал небольшое сообщение (28 байт), никаких проблем не будет.
А что если клиент отправит сообщение, превышающее по размеру 1024 байт — скажем, 1 мегабайт? Например, так:
write(fd, buf, 1000000);
Как сервер мог бы обработать это сообщение поизящнее? Мы могли, к примеру, сказать, что клиенту не позволяется записывать более чем n байт. Тогда функции write() в клиентской Си-библиотеке пришлось бы разбивать каждый «длинный» запрос на несколько запросов по n байт каждый. Неуклюже.
Другая проблема в этом примере заключается в вопросе «А каково должно быть n ?»
Как вы видите, этот подход имеет следующие основные недостатки:
• Все функции, которые применяются для обмена сообщениями ограниченного размера, должны быть модифицированы в Си- библиотеке так, чтобы функция передавала запросы в виде серии пакетов. Это само по себе немалый объем работы. Также это может иметь ряд неожиданных побочных эффектов при работе в мнопоточной среде — что если первая часть сообщения от одного потока передана, и тут его вытесняет другой поток клиента и посылает свое собственное сообщение. Что будет с прерванным потоком тогда?
• Все серверы должны быть готовы к обработке сообщения максимально возможного размера. Это означает, что все серверы должны будут иметь значительные области данных, или Си-библиотека будет должна разделять большие запросы на несколько меньших, ухудшая тем самым быстродействие.
Читать дальшеИнтервал:
Закладка: