СЕТЕВАЯ ОПЕРАЦИОННАЯ СИСТЕМА QNX Обзор системы Санкт-Петербург 1991 2 СОДЕРЖАНИЕ стр. 1. Обзор операционной системы QNX 3 1.1. Модель программиста 3 2. Среда разработки 12 2.1. Редактирование 12 2.2. Компилирование 12 3. Базовые системные вызовы 14 3.1. Функции создания и управления задачами 14 3.2. Файловые функции ввода/вывода 14 3.3. Функции сообщений и сигналов 14 3.4. Функции экрана и клавиатуры 15 3.5. Функции времени 16 4. Проектирование программ и систем 17 4.1. Взамосвязи 17 4.2. Ресурсы 18 4.3. Уровни 20 4.4. Многозадачность 21 4.5. Синхронизация 23 5. Команды операционной системы QNX 25 5.1. Консоли и терминалы 25 5.2. Текстовые команды 26 5.3. Файловые команды 26 5.4. Команды задач 27 5.5. Сетевые команды 28 5.6. Печать 28 5.7. Файлы инициализации 28 5.8. Управление дисками 29 Заключение 30 3 1. ОБЗОР ОПЕРАЦИОННОЙ СИСТЕМЫ QNX 1.1. Модель программиста Любая компьютерная система является комбинацией различных компонент. С точки зрения QNX, например, это может быть набор центральных процессоров, оперативной памяти, локальной вычислительной сети, операционной системы и программ на языке Cи. В то время как с этой точки зрения от программиста, возможно, потребуются знания о вещах, отличных от программирования (например об аппаратных средствах), QNX обеспечивает более абстрактный взгляд на систему. На этом уровне система проявляет себя просто как набор задач, сообщений и ресурсов. Задачи - это исполняемые блоки, которые оперируют над ресурсами и взаимодействуют через сообщения. Обычным ресурсом является оперативная память, файлы и т.д., в общем, Си-структуры данных. Иногда необходимо также знать об узлах, но они могут быть проигнорированы даже в сложных распределенных приложениях. В QNX две задачи на различных узлах могут взаимодействовать вполне успешно без знания того, что они разделены. Во многих случаях QNX подобна MS-DOS, UNIX и многим другим традиционным операционным системам. Она реализует больше возможностей, чем одни, и меньше, чем другие. Конкретно в ней реализованы: - многозадачность. Возможность выполнять несколько различных копий кода, каждый из которых имеет свои собственные данные, на одной и той же машине в одно и то же время; - реальное время. Подразумевается, что система может отвечать на данное событие за определенный промежуток времени (т.е. время может быть переменным, но всегда будет иметь определенный верхний предел); - файловая система. Иерархический набор файлов, содержащих программы и данные, и каталогов, содержащих информацию о файлах и других каталогах; - устройства. Доступ к внешней памяти (например, к дискам) и внешнему миру (например, терминалам) через хорошо определенные независимые от устройств структуры; - распределенность. Т.е. приложение может быть распространено на несколько физических узлов; различные части приложения могут взаимодействовать достаточно спокойно, не сознавая, что они находятся на различных машинах; - взаимодействие между процессами. Межпроцессное взаимодействие позволяет любой задаче взаимодействовать (обмениваться данными) с любой другой задачей. Все эти компоненты доступны из программ, написанных на языке программирования Cи (в дальнейшем для простоты - C-программы), следовательно, все они являются частью модели Cи - "виртуальной машины". Обычная физическая конфигурация компьютеров и связанного с ними оборудования может выглядеть подобно той, которая представлена на рис.1-1. 4 +----------------+ +----------------+ Ё Ё Ё Ё Ё консоль Ё Ё консоль Ё Ё Ё Ё Ё +----------------+ +----------------+ Ё Ё -+ +-------------------+ +-------------------+ дЁ Ё +------+ +------+ Ё Ё +------+ +------+ Ё и+--Ё Ё часы Ё Ё ЦП Ё Ё Ё Ё часы Ё Ё ЦП Ё Ё сЁ Ё +------+ +------+ Ё Ё +------+ +------+ Ё кЁ Ё +---------------+ Ё Ё +---------------+ Ё -+ Ё Ё Оперативная Ё Ё Ё Ё Оперативная Ё Ё Ё Ё память Ё Ё Ё Ё память Ё Ё Ё +---------------+ Ё Ё +---------------+ Ё Ё последовательные Ё Ё последовательные Ё <====> порты Ё <====> порты Ё Ё +---------------+ Ё Ё +---------------+ Ё Ё Ё Сетевая Ё Ё Ё Ё Сетевая Ё Ё Ё Ё плата Ё Ё Ё Ё плата Ё Ё Ё +---------------+ Ё Ё +---------------+ Ё Ё Ё Ё Ё Ё Ё +---------+---------+ +---------+---------+ Ё Ё +------------------------------------------- - - - ЛВС Рис.1-1. "Физический компьютер" С точки зрения программиста, с другой стороны, эта конфигурация выглядит следующим образом: +--------------------------------------------------------- - - -- Ё +----------+ +----------+ Ё +----------+ +----------+ Ё ЁустройствоЁ ЁустройствоЁ Ё ЁустройствоЁ ЁустройствоЁ Ё +----------+ +----^-----+ Ё +----------+ +----------+ Ё Ё Ё Ё Ё +------+ Ё Ё +------+ +-------- Ё ЁзадачаЁ Ё Ё ЁзадачаЁ Ё +^-^---+ +------+ Ё +---^--+ Ё Ё Ё ЁзадачаЁ<---+-------+ +---------+ Ё Ё +-----+ +------+<---+------------+ +--v---+ Ё Ё Ё +-------+------------------>ЁзадачаЁ Ё Ё +--v---+ Ё Ё +--^---+ Ё Ё ЁзадачаЁ Ё Ё Ё Ё Ё +------+ Ё Ё Ё Ё +v---+ +----+ +-v--+ Ё +----+ +----+ +-v--+ Ё ЁфайлЁ ЁфайлЁ ЁфайлЁ Ё ЁфайлЁ ЁфайлЁ ЁфайлЁ Ё +----+ +----+ +----+ Ё +----+ +----+ +----+ +--------------------------------------------------------- - - -- (узел) (узел) Рис. 1-2. "Виртуальный" компьютер Таким образом, вся система представляется как единственный компьютер, состоящий, главным образом, из задач, файлов и 5 устройств. Границы между узлами очевидны, но не видимы в модели программиста, что позволяет задачам взаимодействовать с задачами и файлами на других узлах без дополнительных усилий. Диски и принтеры также присутствуют, но доступ к ним осуществляется как к обобщенным устройствам через библиотеку стандартных интерфейсных функций. Для программиста задача является единственным планируемым блоком работы. Другими словами, задача содержит исполнительный код и личные данные, которые доступны только этой задаче. Большую часть времени задачи выполняются независимо друг от друга, переходя в сотояние ожидания (или блокировки) только тогда, когда им необходимо синхронизироваться с другими задачами или ресурсами. Управление последовательностью выполнения задач в операционной системе базируется на таком диалоге и на предварительно определенном приоритете. Данная задача может выполняться только в течение короткого промежутка времени (называемого отрезком - slice). После чего будет выполняться следующая ожидающая задача с тем же самым приоритетом. (Низкоприоритетные задачи блокируются задачами с более высоким приоритетом до тех пор, пока блок высокоприоритетной задачи занят выполнением операции ввода/вывода или другой операции.) Задачи с высоким приоритетом выполняются сразу, как только они становятся готовы к выполнению, удаляя задачи с более низким приоритетом. Т.е., отрезок времени задачи с низким приоритетом может быть принудительно укорочен.) Имя загрузочного файла задачи становится именем задачи, когда она выполняется, и не обязательно должно быть уникальным. В узле (но не по всей сети) задачи идентифицируются уникально идентификатором задачи, который назначается операционной системой во время создания задачи. Кроме того, задача может быть зарегистрирована в системе под более общим именем, например "eventlog", так что другие задачи могут легко ссылаться на нее. В QNX все задачи создаются другими задачами. То есть, задача A создает задачу B. Задача A может быть интерпретатором команд, а B - командой, например "copy" (копировать). Или задача A может быть прикладной программой, а задача B - утилитой сортировки. Взаимодействие между задачами A и B определяется задачей A, когда она создает задачу B. Задача A может сделать задачу B зависимой, порожденной новой версией; в этом случае выполнение задачи A будет приостанавливаться до завершения задачи B. И наоборот, B может быть конкурентно порожденной и обе задачи будут выполняться параллельно. В этом случае задача B может завершиться в любое время, не оказывая влияние на задачу A. В обоих ситуациях задача B будет завершаться аварийно, если задача A будет завершаться по любой причине. Третья возможность - это, когда обе задачи полностью независимы; в этом случае завершение любой из задач не оказывает влияния на другую. В любой данный момент времени задача выполняется, блокируется или безжизненна (т.е. только что завершена или находится в состоянии завершения). Таким образом, задача всегда находится в одном из немногих состояний. Во время своего выполнения задача переключается между состояниями по несколько раз, обычно это происходит в результате побочного эффекта попытки передать или 6 принять сообщение. Представленная ниже диаграмма показывает возможные состояния одной задачи (например, 'A') и отражает события, которые вызывают переход задачи из одного состояния в другое. A передает сооб- +----------------------+щение к B +----------------------+ Ё +----------------> Ё Ё Задача готова Ё B отвечает Ё Задача блокируется Ё Ё <----------------Ё передачей Ё +-----^----------------+ +----------------------+ Ё Ё Ё ЁA запрашивает сообщение Ё Ё Ёлюбая задачЁа передает сообщение +-----------------v----+ Ё Ё Ё Задача блокируется Ё Ё приемом Ё +----------------------+ Рис. 1-3. Состояния задачи QNX ссылается на состояние "выполнение", как находящаяся в состоянии "готова". Это означает, что даже когда задача не заблокирована, или наоборот, приостановлена, она также имеет возможность использовать процессор совместно с другими задачами. QNX будет предоставлять процессор по очереди каждой готовой задаче на несколько сотых долей секунды - отрезок процессорного времени. Разделение времени хорошо приложимо к многопользовательским средам. Каждому пользователю гарантируется приемлемое время ответа; одна единственная задача не может доминировать в системе. Однако, это обычно конфликтует с нуждами задач реального времени. Для такой ситуации QNX обеспечивает задачам назначение приоритетов. Задача с высоким приоритетом никогда не отдаст процессор задаче с более низким приоритетом. Разделение времени поддерживается только для задач, имеющих равный приоритет. Обе возможности, разделение времени и приоритет, могут изменяться для достижения хорошей настройки производительности конкретной системы. Файловая система организована в виде иерархической древовидной структуры каталогов, растущей из корня данного диска. Файлы содержат данные и могут находиться на любом уровне иерархии, т.е. в любом каталоге. Каталоги содержат информацию о файлах - такую, как их имена и тип доступа - и информацию о других каталогах. Каталоги подобны "ящикам" - пользователь может иметь ящики внутри ящиков до любой глубины вложенности. (Заметим, что QNX не допускает наличия пустых файлов. Любой файл, длина которого после некоторой обработки становится нулевой, автоматически удаляется.) Файлы и каталоги имеют свои имена. ЛВС Узлы являются заметными средствами многих установок QNX. Они обеспечивают отдельные рабочие станции в общем случае, областями, которые им необходимы. Т.е. каждый узел поддерживает приложения, 7 связанные с конретной функцией работы (производственный процесс, программисты и т.д.). В то же самое время узлы могут совместно использовать такие ресурсы, как диски или принтеры, которые обычно являются собственностью "серверных" узлов. Узлы соединяются друг с другом через Локальную Вычислительную Сеть (ЛВС). С другой стороны, модель программиста исключает, насколько это возможно, влияние наличия сети на разработку приложений. Вместо трактовки сети как набора взаимосвязанных, но различных компьютеров, для программиста более удобно рассматривать всю систему как единственную "виртуальную машину", которая физически распределена по широкой области. Все задачи полагают, что они работают на этой единственной машине, а все файлы считаются доступными, как если бы они располагались на этой машине. Основное различие между этой идеальной точкой зрения и истинным одномашинным компьютером заключается в том, что время перемещения данных между задачами существенно меняется. Узлы идентифицируются номерами в диапазоне от 1 до 255, причем узел 1 - это обычно основная машина. Задачи могут обращаться к узлам неявно, позволяя операционной системе выполнять поиск специфицированной задачи или файла, или они могут специфицировать конкретный узел в явном виде. Обеспечение прозрачности ЛВС по отношению к задачам является существенной частью философии QNX и становится возможным только вследствие того, что она опирается на механизм передачи сообщений. Так как сообщение является дискретным квантом данных, в отличие от задач, то необходимо вмешательство операционной системы, чтобы определить, как его перемещать между задачами. Совместно используемая память и другие традиционные механизмы связывают две задачи вместе и поддерживают их совместное существование в одном и том же узле. Такая технология имеет место в системе реального времени, но не соответствут требованиям сети. Устойчивое соединение задач также ставит вопрос о синхронизации и защите, оба из которых четко решаются сообщениями. Подробно передача сообщений будет рассмотрена чуть позже. Технически QNX ЛВС - QNX-сеть - является сетью, базируемой на протоколе ARCnet, который является протоколом кольца с маркерной передачей IEEE 802.5. Электронный "маркер" передается от узла к узлу. Всякий раз, когда узел получает маркер, он может послать пакет или, если у него ничего нет для передачи, он передает маркер к следующему узлу. Номинальная скорость передачи данных - 2.5 мегабита в секунду, хотя актуальная пропускная способность - измеренная скорость передачи данных - несколько ниже (около 1 мегабита в секунду). Пропускная способность определяется прежде всего размером передаваемых сообщений. Более короткие сообщения требуют больше времени на установку и координацию относительно объема передаваемой информации, чем для длинных сообщений. Более длинные сообщения лучше используют передающую среду, но загружают сеть на более длительный период времени, тем самым влияя на пропускную способность других сообщений. С точки зрения программиста нет необходимости обращать внимание 8 на сеть, как на таковую. Однако, эти характеристики необходимо учитывать. Следует обратить внимание на: - различие времени передачи сообщений между задачами, находящимися на различных узлах, по сравнению с задачами, находящимися на одном и том же узле; - возможность отказа узла, с которым выполняется обмен сообщениями. Виртуальный канал Более тонкое влияние на ЛВС оказывает передача сообщений между узлами. Когда задачи находятся на одном узле, то QNX просто копирует данные от одной задачи к другой. Когда сообщение передается к удаленной задаче, QNX создает виртуальную задачу на обоих узлах, чтобы представить передающую и принимающую задачи. Вместе две виртуальные задачи используют виртуальный канал. Каждая "реальная" задача может взаимодействовать с локальным суррогатом другой задачи, а операционная система будет заботиться о достижении другой "реальной" задачи. Заметим, что оригинальный передатчик отвечает за установку виртуального канала, в то время как приемник вообще не подозревает, что передатчик удаленный. Взаимодействие между задачами QNX имеет шесть основных механизмов для перемещения информации между задачами: 1) Прямой доступ к совместно используемой памяти. 2) Файлы. 3) Сообщения (т.е. пакеты данных). 4) Поименованные очереди (сообщений). 5) Порты (которые позволяют формировать сигнал одного конкретного условия). 6) Исключения. Совместно используемая память В QNX вся распределенная память является собственностью активных задач. "Совместно используемая память" означает, что по крайней мере одна посторонняя задача имеет прямой доступ посредством указателей к данным в задаче, которая является собственником этих данных. Конечно, это работает только тогда, когда все рассматриваемые задачи находятся на одном и том же узле. Хотя совместно используемая память - это самый быстрый способ обмена данными, но он не свободен от возникновения ошибок, если не предусмотрены меры по синхронизации доступа. Совместно используемые файлы Файлы чаще всего используются для хранения конечных результатов шагов обработки и для передачи к следующему шагу: например, сортировка файла, а затем вывод его на печать. Совместно используемый файл в реальном времени представляет те же проблемы синхронизации, что и совместно используемая память. Хотя отдельные транзакции обрабатываются последовательно, т.е. обработка одной транзакции завершается прежде, чем начинается обработка другой, но все равно нет никаких гарантий содержания файла в целом. В зависимости от сложности диалога может быть 9 затребована любая, вплоть до полностью ориентированной на транзакции, база данных. Так как файлы являются внешними по отношению к задачам, то они могут быть захвачены на любом узле. Достоинством файлов является тот факт, что они могут сохранять данные, даже если будет выключено питание. Сообщения Сообщения отличаются количеством данных ("пакет", если хотите), которые передаются от одной задачи точно к другой задаче. Данные копируются из адресного пространства первой задачи в адресное пространство второй и выполнение первой задачи приостанавливается до тех пор, пока вторая задача не вернет ответное сообщение. В действительности обе задачи кратковременно взаимодействуют во время выполнения передачи. Ничто, кроме длины сообщения (максимальная длина 65535 байт), не заботит QNX при передаче сообщения. Существует несколько протоколов, которые могут быть использованы для сообщений. Основные операции над сообщениями - это послать, получить и ответить, а также несколько их вариантов для обработки специальных ситуаций. Получатель всегда идентифицируется своим идентификатором задачи, хотя существуют способы ассоциировать имена с идентификатором задачи. Наиболее интересные варианты операций включают в себя возможность получать (копировать) только первую часть сообщения, а затем получать оставшуюся часть такими кусками, какие потребуются. Это может быть использовано для того, чтобы сначала узнать длину сообщения, а затем динамически распределить принимающий буфер. Если необходимо задержать ответное сообщение до тех пор, пока не будет получено и обработано другое сообщение, то чтение первых нескольких байт дает вам компактный "обработчик", через который позже можно получить доступ ко всему сообщению. Таким образом, ваша задача предохраняется от того, чтобы хранить в себе большое количество буферов. Другие функции позволяют программе получать сообщения только тогда, когда она уже ожидает их приема, а не блокироваться до тех пор, пока не прибудет сообщение, и транслировать сообщение к другой задаче без изменения идентификатора передатчика. Задача, которая транслировала сообщение, в транзакции невидима. Очереди QNX обеспечивает объединение сообщений в структуру данных, называемую очередью. Очередь - это просто область данных в третьей, отдельной задаче, которая временно принимает передаваемое сообщение и немедленно отвечает передатчику. В отличие от стандартной передачи сообщений, передатчик немедленно освобождается для того, чтобы продолжить свою работу. Задача администратора очереди хранит в себе сообщение до тех пор, пока приемник не будет готов прочитать его; это он делает путем запроса сообщения у администратора очереди. Любое количество сообщений (ограничено только возможностью памяти) может храниться в очереди. Они хранятся и передаются в том порядке, в котором они были приняты. Может быть создано любое количество очередей. Каждая очередь идентифицируется своим именем. 10 Порты Порт подобен флагу, известному всем задачам на одном и том же узле (но не на различных узлах). Он имеет точно два состояния, которые могут трактоваться как "присоединить" и "освободить", хотя пользователь может использовать свою интерпретацию; например, "занят" и "доступен". Порты используются для быстрой простой синхронизации между задачей и обработчиком прерываний устройства. Они нумеруются от нуля до максимум 32 (на некоторых типах узлов возможно и больше). Первые 20 номеров зарезервированы для использования операционной системой. С портом может быть выполнено три операции: - присоединить порт, - отсоединить порт, - послать сигнал в порт. Одновременно к порту может быть присоединена только одна задача. Если другая задача попытается "отсоединиться" от того же самого порта, то произойдет отказ при вызове функции, и управление вернется к задаче, которая текуще присоединена к этому порту. Это самый быстрый способ обнаружить идентификатор другой задачи, подразумевая, что задачи могут договориться использовать один номер порта. Помните, что все рассматриваемые задачи должны находиться на одном и том же узле. При работе нескольких узлов специальные функции обеспечивают большую гибкость и эффективность. Любая задача может посылать сигнал в любой порт независимо от того, была ли она присоединена к нему, или нет (предпочтительно, чтобы не была присоединена). Сигнал подобен неблокирующей передаче пустого сообщения. То есть, передатчик не приостанавливается, а приемник не получает какие-либо данные; он только отмечает, что конкретный порт изменил свое состояние. Задача, присоединенная к порту, может ожидать прибытия сигнала или может периодически читать порт. QNX хранит траекторию количества сигналов, передаваемых в каждый порт, и уменьшает счетчик после каждой операции "приема" сигнала ("чтение" возвращет счетчик и устанавливает его в нуль). Сигналы всегда принимаются перед сообщениями, давая им тем самым больший приоритет над сообщениями. В этом смысле сигналы часто используются обработчиками прерываний для того, чтобы оповестить задачу о внешних (аппаратных) событиях. (Действительно, обработчики прерываний не имеют возможности посылать сообщения и должны использовать сигналы. В отличие от описанных выше методов, которые строго синхронизируются, "исключения" обеспечивают асинхронное взаимодействие. То есть, исключение может прервать нормальное выполнение потока задачи. Они, таким образом, являются аварийными событиями. QNX резервирует для себя 16 исключений для того, чтобы оповещать задачи о прерывании с клавиатуры, нарушении памяти и подобных необычных ситуациях. Следующие 16 исключений могут быть определены и использованы прикладными задачами. (Нормальное действие, когда исключение возникает для того, чтобы аварийно завершить соответствующую задачу. Задача должна обратить внимание на возникновение исключения, чтобы обработать исключения, 11 известные операционной системе, прежде, чем они возникнут, если задача хочет предотвратить свое аварийное завершение.) Системная функция может быть вызвана для того, чтобы позволить задаче управлять своей собственной обработкой исключений, выполняя свою собственную внутреннюю функцию во время возникновения исключения. Заметим, что функция исключения задачи вызывается асинхронно операционной системой, а не самой задачей. Вследствие этого и поэтому исключения могут иметь сильнодействующее побочное влияние на операции (например, передачу сообщений), которые выполняются в это же время. Обработчики исключений должны быть написаны очень аккуратно. Одна задача может установить одно или несколько исключений на другой задаче. Они могут быть комбинацией системных исключений (определенных выше) и исключений, определяемых приложениями, обеспечивая другие возможности для межзадачного взаимодействия. 12 2. СРЕДА РАЗРАБОТКИ И наконец о программировании. Программирование - это не только написание кода, это еще и средства редактирования, компилирования и создания резервных копий. Кроме того, сюда включается тестирование и отладка программ. 2.1. Редактирование Стандартный в системе QNX программный редактор - это полноэкранный текстовой редактор. Он отображает строку состояния и командную строку в верхней части экрана и отображает страницу текста на остальной части экрана. Пользователь может перемещать курсор в любую позицию экрана и удалять знаки и строки, на которые указывает курсор, или вводить новый текст. Блоки текста можно перемещать, копировать или сохранять в другом файле. Экран действует как окно на текстовом файле, так что можно перелистывать файл по строкам или по страницам. Существуют ограничения на длину строки и количество строк в файле, но эти ограничения незаметны для пользователя. Редактор содержит такие функции, свойственные текстовым поцессорам, как центрирование текста и т.п. 2.2. Компилирование Фирма Quantum поставляет в составе операционной системы многопроходный оптимизирующий компилятор языка Си. Компилятор выполняет некоторые шаги, каждый из которых генерирует вывод в файлы, которые затем читаются следующим шагом. Последний шаг связывает объектные модули программы с системными библиотечными модулями для создания исполнительного файла. Компилятор Си поддерживает базовые K & R определения языка. (Он не поддерживает ANSI стандарт, хотя и добавлен перечисляемый тип данных.) Знаки содержат восемь бит и имеют длину 32. В нем нет различия между короткими и стандартными целыми числами; оба этих типа представляются 16 битами. Числа с плавающей точкой и двойной точностью имеют длину 32 и 64 бита соответственно. Компилятор Си фирмы Quantum поддерживает только "малую", или "компактную" (в зависимости от принятой терминологии) модель для задач. Т.е. результирующий код задачи и данные не должны превышать 64К байта каждый. Однако, компилятор допускает дополнительные сегменты, распределяемые и управляемые программой. Тем не менее, ограничение в 64 К байт не является критическим. В действительности оно может быть рассмотрено как достоинство. QNX основывается на философии использования нескольких небольших специализированных задач, которые совместно работают в сложных прикладных системах. Небольшая задача быстрее загружается (особенно в ЛВС) и использует простые 16-ти битовые (или слово) указатели. Однословный указатель сравнивается и вычисляется проще и быстрее, чем двусловные операции, которые требуются на большом адресном пространстве. В общем случае, приложения, скомпонованные из небольших задач, будут яснее и более гибкими, чем единственная огромная задача. Но все-таки следует заметить, что существует возможность иметь сегменты кода и данных больше 64К байт, если пользователю все-таки это потребуется. 13 3. БАЗОВЫЕ СИСТЕМНЫЕ ВЫЗОВЫ 3.1. Функции создания и управления задачами Все задачи создаются другими задачами. Например, интерпретатор командной строки создает задачи, набираемые пользователем в командной строке. Если пользователь хочет написать программу, которая запускает другую задачу, то он имеет возможность выбрать одну из следующих возможностей: 1) Создать полностью новую задачу. Новая задача может быть полностью независимой от создателя, или она может быть подзадачей (дочерней). В последнем случае создатель может решить заблокироваться до тех пор, пока не завершится подзадача. Если создатель завершается первым, то подзадача может быть автоматически уничтожена в результате побочного эффекта. 2) Заместить текущую задачу новой, сохраняя оригинальный идентификатор задачи. Родительская задача завершается. (QNX называет это "замена на другую задачу".) 3) Расщепление текущей задачи на две задачи, т.е. разделение оригинальной задачи. (QNX называет это "разветвлением задачи"). В большинстве случаев явные аргументы могут быть переданы новой задаче. Иногда передается и полная командная строка (в том виде, как ее набрал пользователь на терминале). QNX будет создавать оболочку интерпретатора командной строки для анализа аргументов перед передачей их задаче. 3.2. Файловые функции ввода/вывода QNX поддерживает модель файловой системы, принятой в популярной операционной системе UNIX. Другими словами, файлы являются произвольными массивами байт. При хранении на диске файлы размещаются в иерархических каталогах. Однако, большинство устройств, подобных терминалам и принтерам, также трактуются как файлы. На самом низком уровне файлового ввода/вывода (также называемого вводом/выводом потока) непосредственно доступен каждый байт. Все файлы должны быть открыты прежде, чем к ним будет осуществлен доступ, или они должны быть созданы, если они не существуют. Данные могут быть записаны и прочитаны. И, наконец, когда программа завершает свою работу с файлами, то она должна их закрыть. Текстовые файлы QNX содержат "строки" переменной длины. Каждая строка завершается кодом 1Eh (в отличие от MS-DOS и UNIX). 3.3. Функции сообщений и сигналов Вся QNX система зависит от очень многих вызовов ядра для обеспечения межзадачного взаимодействия. Даже системные задачи используют те же самые вызовы, которые применяются и пользователями. Их применение делает программирующий интерфейс простым и ясным, и в то же самое время обеспечивает доступ ко всем задачам в сети. Большая часть взаимодействий между задачами 14 выполняется через сообщения, которые являются "пакетами" данных переменной длины. По существу сигналы являются "пустыми" сообщениями. Т.е. прибытие сигнала само по себе говорит о возникновении события. Только три основных действия может выполнять пользователь с сообщениями: 1) Послать сообщение - определить последовательность байт и идентифицировать задачу, которая должна принять сообщение. 2) Получить сообщение - копировать последовательность байт в свой собственный буфер. 3) Ответить на сообщение - копировать последовательность байт назад к исходному передатчику этого сообщения для того, чтобы освободить его для дальнейшей работы. 3.4. Функции экрана и клавиатуры Существует мало программ, которые бы время от времени не взаимодействовали с человеком. Или посредством простого интерпретатора командной строки, или с помощью сложной графической оболочки, человеческий интерфейс является ключевой компонентой. Методы, которые выбирает программист для диалога с пользователем, обычно являются результатом сложной комбинации факторов и индивидуального отношения к ним. После того, как решен вопрос, какой будет интерфейс, программист будет иметь дело с консолями и терминалами. Консолью мы будем называть экран и клавиатуру, "встроенные" в узел. Экран управляется графическим адаптером, установленным в компьютер. Узел может также иметь один или несколько терминалов, присоединенных к нему через последовательные разъемы, которые вставляются в заднюю стенку компьютера. Основные различия заключаются в следующем: - консоли обычно являются графическими устройствами (кроме текста, они могут рисовать диагональные линии, окружности и т.д., с соответствующим программным обеспечением); терминалы являются только знаковыми устройствами; - консоли могут работать быстрее, так как они являются существенной частью компьютера; терминалы же ограничены скоростью последовательного соединения, например, 9600 бод (приблизительно тысяча знаков в секунду). С точки зрения программиста, консоли и терминалы очень похожи. В большинстве случаев они ведут себя подобно стандартным потоковым устройствам, описанным ранее в этом разделе. Если планируется трактовать ввод с клавиатуры и вывод на экран как строки текста, то программист уже знает все, что необходимо знать. С другой стороны, если требуется отображать графику, то можно воспользоваться преимуществами библиотеки QNX, содержащей 15 независимые от устройств экранные функции. Они используют расширенные ASCII знаки (значение кодов которых больше 127 (десятичное)) для отображения прямоугольников, линий, меню и т.д. Существует два набора функций: один для терминалов и один для консолей. Формирователь может быть использован на консоли или терминале, для которого существует элемент в файле "tcap". Второй набор функций предназначен только для консолей и записывает непосредственно (и очень быстро) в память графического адаптера. Определенная совместно используемая библиотека должна быть установлена для конкретного адаптера, используемого в машине. База данных tcap содержит определения терминальных устройств для того, чтобы QNX могла найти для каждой конкретной модели ответ на вопрос: как очистить экран, как переместить курсор и т.д. 3.5. Функции времени Задачи, которые имеют дело со временем, обычно хотят определить превышение текущей даты и времени, измерить течение события или ожидать, пока не пройдет некоторый интервал времени. QNX поддерживает набор стандартных (UNIX-совместимых) библиотечных функций, плюс некоторые расширения. 16 4. ПРОЕКТИРОВАНИЕ ПРОГРАММ И СИСТЕМ В этом разделе будет показано, как две или больше задач могут работать вместе. Понимание взаимосвязи является существенным для написания программного обеспечения в QNX. Взаимосвязи существуют не только между задачами и другими ресурсами, например файлами. Сообщения - это первичная среда, которая связывает ресурсы внутри взаимосвязи. Проект самой QNX поощряет к созданию элегантных приложений, но, как будет показано, за некоторую цену. Здесь внимание будет сфокусировано на проектировании систем, состоящих из двух и более задач, а не на проектировании программ. Здесь будут рассмотрены потоки данных между задачами, синхронизация между ними и некоторые из ограничений реального времени, налагаемые операционной системой. 4.1. Взамосвязи Если программист уже писал программы на языке, используя библиотечные функции в среде операционных систем MS-DOS, UNIX и т.д. то он сможет легко написать программу и в QNX. Существует большое количество способов просмотреть взимосвязи между двумя и более задачами. Обычно взаимосвязь подразумевает для диалога набор правил, часто называемый протоколом. Протокол может быть очень простым или довольно сложным. (Однако не имеет значения, насколько он прост; протокол всегда должен быть хорошо определен, особенно, если задачи пишутся различными людьми.). Ниже представлены некоторые виды взаимосвязей: - пользователь/инструмент Пользовательская задача создает инструментальную подзадачу для выполнения общей функции: например, сортировки файла; инструментальная задача завершается, когда она выполнена (это подобно вызову библиотечной функции, но на более высоком уровне; "аргументы" передаются через сообщения, хотя большие объемы данных обычно записываются в файл.) - пользователь/инструмент/пользователь Это вариант описанной выше взаимосвязи, где одна задача посылает данные другой косвенно, через промежуточную задачу, которая выполняет некоторое преобразование данных; в этом сценарии инструмент обычно называется фильтром. - пользователь/сервер В этом случае задача "сервера" всегда активна и выполняет по требованию операции для различных пользовательских задач; примером может служить спулер (накопитель) принтера, администратор оконной системы и база данных; часто сервер может быть характеризован как администратор конкретного ресурса (принтеров, экранов, данных и т.д.). - пользователь/пользователь Вовлекаемые во взаимодействие задачи равноправны и взаимосвязь у них обычно транзиентна или "сильносвязана"; две или несколько задач, которые выполняют основные функции, время от времени 17 решают обменяться информацией (это программный аналог узлов в сети). Реально существует два вида взаимодействия типа пользователь/пользователь: в одном случае задача может просто послать запрос к другой задаче, когда возникнет необходимость; в другом случае, две задачи могут наладить контакт и стать временно тесно связанными, пока они обмениваются серией транзакций, а затем рассоединиться. Беря сетевую терминологию, это можно было бы назвать "дейтаграммой" или "виртуальным каналом" соответственно (но заметим, что QNX использует термин "виртуальный канал" для обозначения нечто другого). Заметим, что это не формальные конструкции QNX, а способ интерпретации базовых механизмов QNX по созданию задач и взаимодействию между ними. Первый - это пример "дочерней" задачи. Второй мог бы быть примером "цепочки" или "ветвления", а третий мог бы быть использован как "администратор". Задачи, использующие модель связи "пользователь/пользователь", могут быть созданы независимо и могут находить связь друг с другом через порт или поименованный сервер. Проектирование приложений для QNX обычно означает назначение задачам операций, определение взаимосвязи между задачами, а затем определение протоколов взаимодействия между ними. 4.2. Ресурсы С точки зрения программиста, система является набором ресурсов: - задачи, - сообщения, - память, - время, - файлы, - консоли, - принтеры. Могут быть и другие ресурсы, но эти являются главными. Задача в QNX - это базовая планируемая единица выполнения. Она содержит исполнительный код и собственные данные. Сообщения - это транзиентная структура данных, главная цель которой - это передача данных между задачами. Кроме того, передача и прием сообщения обеспечивают встроенный механизм синхронизации. Ключевой момент, который нужно помнить о сообщениях - это то, что они переносят как данные, так и управление. Стандартная передача и прием сообщений в QNX синхронизированы; передатчик всегда ждет до тех пор, пока не ответит приемник. Когда используются сообщения, выполнение вовлеченных задач становится последовательным или связанным. Эта потенциальная (и временная) потеря параллелилизма является единственной ценой, которую программист платит за большую надежность системы. Альтернатива - постановка сообщений в очередь, чтобы обе задачи могли работать со своей оптимальной скоростью - очень часто привлекательна и необходима. 18 Память обычно доступна через переменные и структуры данных. Программист не должны знать "память" или беспокоиться об управлении ресурсами памяти. Однако Си позволяет программисту распределять, и в дальнейшем освобождать локальную память областями переменной длины (но смежными). Во всех случаях с точки зрения программиста, память является "местом хранения данных". Это в противоположность самой операционной системе, которая использует память для различных целей, например для исполнительного кода. Если используется набор данных размером больше 64К байт, то у пограммиста возникает проблема. Компилятор фирмы Quantum не может управлять данными, занимающими несколько сегментов. Существует несколько альтернатив для обработки этой ситуации, включая управление своими собственными сегментами. Время тоже является ресурсом. Подобно памяти и другим ресурсам, программист может сам управлять временем, или может решить игнорировать его, и жить со средствами управления временем, принятыми по умолчанию, обеспечиваемыми операционной системой. Время особенно важно, когда имеют дело с приложениями, которые распространяются на несколько узлов. В то время, как взаимодействие задача-задача на единственном узле может рассматриваться как "мгновенное", взаимодействие между узлами в таком виде рассматриваться не может. Время управляется непосредственно установкой и/или чтением таймера. Конечно, все, что делает программист, оказывает некоторое влияние на время; так ему может потребоваться рассматривать приоритеты задачи, сетевую топологию, протоколы сообщений и т.п. в своей разработке. Файлы подобны "внешней памяти". Они хранят данные обычно в довольно больших объемах и более длительные периоды времени. Файлам присваиваются имена таким образом, чтобы они позднее могли быть легко найдены, а также могли бы быть найдены другими программами, которые не создававли эти файлы. Имена файлов могут быть организованы в древовидную иерархическую структуру, называемую каталогом. Подобно памяти, файлы должны управляться программами, но в этом случае программы для того, чтобы сделать это, должны быть частью операционной системы. Каждый узел может иметь устройство консоли. Узел может иногда и не иметь консоли, но это бывает редко. Консоль состоит из экрана, присоединенного непосредственно к дисплейному адаптеру внутри компьютера, плюс клавиатура. Могут быть и другие устройства ввода, связанные с консолью: например "мышь" или шаровой манипулятор. Любой узел может также иметь терминалы, присоединенные к нему через последовательные порты. Терминалы имеют в основном возможности консолей, но не могут отображать битовую графику. Принтеры безусловно представляют наиболее традиционное средство пересылки компьютерных данных на бумагу. Наиболее общий тип принтера - это матричный, который печатает знаки и графику в виде массива точек. Принтер присоединяется к параллельному порту компьютера. Принтеры могут быть также присоединены и к последовательному порту компьютера. "Управление ресурсами" - это другой способ назвать 19 "проектирование системы". Многие приложения расходуют большую часть своего времени на генерацию и преобразование данных. Например, база данных принимает данные от пользователя, преобразует их во внутренний формат и сохраняет их в файлах. В дальнейшем пользователи могут запросить базу данных вводом команд, и программа базы данных сканирует данные, обрабатывает их и преобразует результат снова в формат, понятный человеку. Приложения управления процессами накапливают данные и сохраняют их в быстрой базе данных. Отсюда данные используются для генерации отчетов и отображений, и для принятия решения о том, какое влияние может быть оказано на процесс. 4.3. Уровни Программирование в QNX выполняется на двух различных уровнях: 1) Уровень задачи, который является "чистой" Си-программой; 2) Системный уровень (или уровень виртуальной машины), который вызывает диалог нескольких задач. Все задачи, которые используют ресурсы QNX, будут использовать сообщения, хотя их использование не всегда видимо. То есть, передача и прием сообщений могут быть скрыты библиотечными обработчиками. Действительно, каждая задача QNX запускается со следующей логикой: 1. инициализация, 2. неопределенное повторение 2а. ожидание прибытия сообщения, 2б. проверка сообщения и вызов соответствующей функции, 3. очистка 4. выход. Задачи, которые отвечают на сообщения, очень часто называются серверами, так как они обеспечивают обслуживание (сервис) других задач. Сообщение, посылаемое к серверу, является запросом, а результатом обычно является ответ. Задачи, которые посылают запросы, называются клиентами. В обычных системах большинство задач будут иметь отдельные характеристики каждой из таких задач. Т.е. они будут принимать запросы и посылать запросы к другим обслуживающим средствам, таким, как файловая система или консольный драйвер. Шаг 2б обычно включает проверку на появление сообщения "выйти", которое завершает цикл или программу. Задача также должна ответить передающей задаче. Эта логика приводит к чисто управляемому сообщениями проектированию. Однако, это не все. Если задача находится не на самом нижнем уровне иерархии приложения, то ее единственной целью является прием сообщений и возврат ответа, она также будет нуждаться в посылке сообщений другим задачам (например, для того, чтобы прочитать файлы). Следовательно, некоторые функции, вызванные шагом 2б, будут вызывать передачу. Главное, что нужно помнить, это то, что задача выполняется последовательно. Каждый шаг выполняется по очереди, а когда задача посылает сообщение, ее 20 выполнение приостанавливается до тех пор, пока она не получит ответное сообщение. Эта прямолинейность вызывает упрощенность и, возможно, неточность видения реального мира. Ее преимущества заключаются в том, что последовательные программы проще в разработке и отладке, чем конкурирующие программы, где порядок возникновения событий не предсказуем. В традиционных многозадачных операционных системах очевидная конкурентность достигается совместным использованием одного процессора многими задачами. Сетевые системы, подобные QNX, расширяют эту модель до истинной конкурентности со многими процессорами. Две задачи на различных узлах реально выполняются в одно и то же время. Большая часть разработки системы определяет, сколько задач должно быть, что они должны делать, где они должны располагаться в сети и как они должны взаимодействовать друг с другом. Это возвращает нас назад к двум точкам зрения на проектирование, которые мы только что ввели: взаимосвязи и ресурсам. Некоторые называют это потоком данных (или управлением данными) и объектно-ориентированным проектированием соответственно. QNX - и, в общем случае, системы с передачей сообщений - непосредственно не поддерживают какую-либо из этих методологий, но они облегчают использование их концепций. 4.4. Многозадачность Если, приступая к работе с QNX, программист уже имел дело с многозадачными операционными системами, то в QNX он найдет много знакомых концепций. Он может обойти этот подраздел. С другой стороны, если программист работал только с DOS или встроенным исполнителем, то он может найти здесь некоторые идеи для программ, выполняющихся "одновременно". (Программисты, которые разрабатывали встроенные приложения реального времени, использовали многозадачность, не зная об этом. Они только выполняли свое собственное распределение ресурсов и распределение своего кода. В QNX вы должны научиться позволять другим программам делать для вас некоторую работу.) Идея многозадачности проста: позволить нескольким программам использовать машину и ресурсы в одно и то же время. Конечно, только одна программа в один момент времени может использовать центральный процессор, поэтому операционная система непрерывно переключается между задачами, давая каждой небольшой отрезок времени центрального процессора. Другими словами, операционная система обеспечивает кажущуюся конкурентность (одновременность). (Каждая задача собирается отдельно и имеет свой собственный "главный" модуль и свою собственную локальную область данных.) Наличие нескольких задач, активных одновременно, открывает новые возможности для разработки приложений, а также создает новые проблемы. Очевидные преимущества заключаются в том, что программист может сделать больше одной работы одновременно: например, отредактировать файл, напечатать отчет и накопить данные с устройства. Так как задачи являются полностью независимыми объектами, то они могут работать с различными приоритетами и взаимодействовать друг с другом по мере 21 необходимости. Главная проблема многозадачности заключается в том, что теперь существует несколько программ, которые потенциально хотят иметь доступ к одному и тому же файлу, принтеру, терминалу и т.д. одновременно. Большинство операционных систем обеспечивают встроенный механизм совместного использования ресурсов. QNX, будучи системой, базируемой на сообщениях, предлагает сравнительно ясный и более гибкий способ синхронизации доступа. Далее этот способ будет рассмотрен более подробно. Все это влияет на способ проектирования приложения. В дополнение к прерыванию спустимся к логическим модулям, которые становятся функциями одной большой программы. Программисту теперь необходимо рассматривать, какие модули могут выполняться параллельно - какие модули могут быть отдельными задачами. Первоначально можно рассматривать задачи как "функции", которые используют сообщения для того, чтобы выполнять "удаленные вызовы функций" к другим задачам (но имейте в виду, что нельзя передавать адреса памяти между задачами). Задачи должны быть активны прежде, чем они будут "вызываны", поэтому нужно решить: или они всегда будут загружены, или лучше их загружать по мере необходимости. В дальнейшем программист может трактовать набор задач как свободно соединенную "сеть" почти так же, как физическую сеть, состоящую из узлов. Подобно хорошо структурированной задаче, существует "корневая" задача, которая запускает другие задачи и управляет ими. Однако, это различие часто становится размытым в многозадачной системе, где задачи выполняются автономно и их роли по отношению к каждой другой задаче могут меняться динамически. Программист также должен быть уверен, что большинство системных ресурсов, таких как файлы, управляются косвенно, через другие задачи. Так, когда вызывается функция "чтение", программист не обращается прямо к дисковому устройству, а выдает запрос к другой программе, которая делает это для него, и посылает ему обратно данные. Задача может конкурировать с другими задачами за одни и те же данные. События реального времени, такие как ввод, управляемый прерываниями, также обрабатываются отдельными задачами. Концепция взаимосвязи, реализуемая операционной системой с интегрированной локальной вычислительной сетью (ЛВС), - это распределенная обработка. Распределенная обработка - это метод совместной работы, обычно с целью получения более быстрого выполнения заданий. (Другой смысл может заключаться в использовании преимуществ специальных возможностей конкретного узла в ЛВС.) Помните, что мы подчеркивали "кажущуюся" одновременность многозадачности - QNX делает так, как-будто несколько программ на одном узле выполняются одновременно. Это возникает вследствие того, что только один процессор выполняет работу. В ЛВС потенциально существует несколько процессоров. Программы, выполняющиеся на различных узлах, реально работают одновременно. Четко спроектированное приложение будет использовать все преимущества этого свойства, посылая определенные части работ в различные узлы, в отличие от выполнения их последовательно, или в режиме простой многозадачности. Сортировка больших файлов, поиск в базе данных, вычисление ходов в шахматах являются типичными приложениями, которым помогла бы их распределенная загрузка. 22 Любой из сценариев, представленных в подраз. 4.1 может быть адаптирован к распределенной обработке. Случаи, когда первая задача создает другие, имееют потенциальную возможность для совместной обработки. Проще говоря, любое программное обеспечение, работающее в сети QNX, является "распределенным". Однако, термин "распределенная обработка" обозначает нечто более специфичное, т.е. несколько задач кооперируются для выполненения конкретного задания. Ключевая характеристика заключается в том, что оригинальная задача должна создавать подзадачи и должна выполняться параллельно с ними. Фокус заключается в проектировании приложения таким образом, чтобы полностью независимые модули распознавались бы и локализовывались. Для программиста, который решает свою проблему последовательно - шаг за шагом - эта грань проектирования не всегда очевидна. Следующая проблема заключается в определении интерфейса к модулям. Преимущество, даваемое параллельным выполнением двух модулей, может быть легко перевешено стоимостью отправки данных по сети и обратно. В третьих, Си не обеспечивает какие-либо механизмы для координации параллельных модулей. Программист должен гарантировать, что "ветви" модулей снова сойдутся вместе перед тем, как последущим модулям потребуются данные, которые, как предполагалось, уже должны быть сформированы. Или же все модули могли бы быть запущены для решения той же самой проблемы, используя различные алгоритмы, или следуя различными путями. Как только одна из них получила решение, другие могут быть завершены. К счастью, QNX поддерживает некоторые функции для обработки истинной конкуренции. 4.5. Синхронизация В любой системе (не только в компьютерных системах) обычно существует несколько участников. Это обычно задачи, но также логично включить в нее и человека - пользователя системы и, в системе реального времени, устройства. (В системах, не поддерживающих реальное время, устройства трактуются как пассивные, подобно файлам; в системах реального времени они работают параллельно и должны рассматриваться раздельно.) В большинстве случаев участники действуют независимо. Однако, в некоторой точке они будут конкурировать за один и тот же ресурс, например дисковый файл, или им потребуется взаимодействие с другими задачами. Это два фундаментальных типа диалога - неявный в сравнении с явным - из которых нужно сделать выбор. Так как мы программисты, то мы будем смотреть на диалог с точки зрения задачи. Исходя из такой перспективы, данная задача говорит другой задаче, осуществляет доступ к ресурсам, вступает в диалог с пользователем и т.д. Общая проблема совместного использования ресурсов заключается в большой заинтересованности. Доступ к ресурсам может быть в широком смысле категоризирован как "запись" и "чтение" - операции, которые или изменяют состояние ресурса, или оставляют его неизменным. Как правило, мы не должны беспокоиться также и об операциях типа чтения. Любое количество задач обычно может просмотреть один и тот же ресурс, хотя это и не всегда истинно. 23 Например, широко используемый ресурс, подобный вводу с клавиатуры, может быть обработан в один и тот же момент времени только одной задачей. Чтение символов из общей области памяти, с другой стороны, может быть выполнено без конфликта. (Заметьте, что мы игнорируем выдачу защиты, которая является отдельной проблемой.) Всякий раз, когда существует возможность для одной задачи выполнить операцию чтения или записи, чтобы случайно не повлиять на другую задачу, операции должны быть синхронизированы. Это означает, что две задачи должны или знать друг о друге и договориться о методе совместного использования ресурсов, или они должны выполнять свои операции через промежуточного агента, который управляет ресурсами. Или же они могут использовать третий ресурс (захват), чтобы управлять доступом. Наиболее легкий способ совместно использовать ресурсы заключается в том, чтобы создать отдельную задачу (называемую задачей-"агентом"), которая управляет ресурсами, и выдавать запросы на ресурс к такой задаче. Затем задача будет выполнять операции одну за другой, гарантируя тем самым, что конфликт не возникнет. Агенты - это более предпочтительный метод синхронизации доступа. Семафоры и критические регионы Если две задачи хотят скооперироваться для совместного использования ресурсов, то им необходим механизм, который мог бы проверять и устанавливать единственную операцию. То есть, задача должна иметь возможность проверить флаг и, если он не установлен, немедленно установить его. 24 5. КОМАНДЫ ОПЕРАЦИОННОЙ СИСТЕМЫ QNX В руководстве по операционной системе описана сотня команд (или утилит). Это программы, которые выполняют различные специфические для операционной системы функции: такие, как монтирование устройств, копирование файлов и т.д. Программы выполняются через интерпретатор (называемый shell), который работает постоянно на каждой консоли и терминале, ожидая от пользователя ввода команды. В этом руководстве также описываются многочисленные способы использования системных устройств (например, консоли) и настройки операционной системы. Средний пользователь никогда не будет использовать все эти команды и средства. Основными командами для разработки программного обеспечения являются: ed - редактирование текстовых файлов; сс - компиляция исходного кода языка Си в двоичные объектные модули; make - управление "проектами", повторно компилируя и связывая файлы, когда это требуется (в зависимости от наличия изменений); backup - создание копий измененных файлов. Кроме того, есть дополнительные команды, которые в меньшей степени относятся к программированию, но потребность в которых время от времени может возникать. Это команды, с помощью которых можно обработать: текст - отсортировать его, найти подстроку, подсчитать количество строк и т.д.; файлы - получить информацию о них, распечатать их содержимое и т.д.; задачи - отобразить их состояние, отменить их выполнение и т.д. В связи с командами используются такие средства, как командные файлы и файлы инициализации. Командный файл по существу та же программа, состоящая из команд, комментариев и переменных оболочки, написанная на простом языке, который легко изучить. Файл инициализации - это командный файл, который выполняется автоматически, когда загружается узел, и используется для запуска некоторых задач и установки некоторых параметров. 5.1. Консоли и терминалы Пользователь взаимодействует с QNX (и с большинством приложений) через консоли и терминалы. Существует несколько программных различий между этими двумя классами устройств. Пользователь заметит меньше таких различий, так как стандартный интерфейс QNX ограничивается вводом команд и текстовым выводом, и не дает возможности использовать какие-либо преимущества уникальных средств этих устройств. В QNX все драйверы устройств "монтируются", т.е. они не встроены в систему, а динамически загружаются в нее. Пользователь может добавлять в систему новые устройства путем монтирования соответствующих драйверов. Обычно пользователь беспокоиться об 25 этом не должен, потому что система сама монтирует основные драйверы, например, для жесткого диска, когда она загружается. Команда mount используется для загрузки дополнительных драйверов, а также для загрузки многочисленных "псевдодрайверов", таких как диски в оперативной памяти (электронный диск) и т.п. Одно из устройств, которое вы можете монтировать вручную - это вторая "консоль". С помощью команды mount можно также вывести список текуще смонтированных устройств, библиотек и т.д. Программа, которая интерпретирует другие команды, называется shell (оболочка), так как она эффективно покрывает внутренние работы системы. Shell - не просто интерпретатор командной строки, она поддерживает свой собственный простой язык программирвания, снабженный переменными и управляющими структурами. Командный файл не настолько гибкий, как программы на языке Cи, но он обычно удовлетворяет основным потребностям. 5.2. Текстовые команды Большая часть программирования состоит из создания и манипулирования текстом. Все команды оболочки QNX создают текст, который отображается на экране, но который также может быть сохранен в текстовом файле путем перенаправления вывода в файл. В состав QNX включены три утилиты, отображающие текстовые файлы: cat - соединение двух или нескольких файлов в единственный файл; по умолчанию вывод направляется на экран; p - вывод файла на экран; more - постраничное отображение файла; Утилиты cat и p выполняют практически одно и то же. Утилита more является более сложной и позволяет "просматривать" файл, используя клавиши перемещения курсора и страницы. wc - это простая команда, которая только подсчитывает количество знаков, слов и строк в одном или нескольких файлах. В QNX можно запросить поиск любого подмножества файлов в текущем каталоге, содержащих конкретную строку, с помощью команды locate. Команда sort копирует строки только из текстового файла и переупорядочивает их в соответствии с заданным критерием. Вывод записывается на стандартное устройство stdout, т.е. на экран, если только он не будет перенаправлен на другое устройство. 5.3. Файловые команды К файловым относятся следующие команды: backup - копирование модифицированных файлов в другой каталог или диск; 26 cd - изменить текущий рабочий каталог; cp - сделать копию файла; ls - список имен файлов в каталоге; pwd - печать текущего рабочего каталога (на экран); rm - удалить файлы. Кроме того, более редко используемые команды: dir - отобразить все каталоги и подкаталоги в виде "дерева"; files - список файлов в каталоге с их атрибутами; mkdir - создать новый каталог; mv - переместить файлы или переименовать один файл; rmdir - удалить каталог. Команда dir обеспечивает быстрый способ просмотреть все файлы в каталоге, и все подкаталоги, лежащие ниже него. Команда files подобна команде ls, но предоставляет больше информации о каждом файле. Подобно dir она выводит список файлов в подкаталогах, а также текущий каталог. Синтаксис команды mv - переместить файлы - подобен команде cp. Главное различие заключается в том, что с mv исходные файлы удаляются после их копирования. Хотя mv обычно используется для перемещения файлов в другие каталоги, она может быть использована для переименования одного файла в текущем каталоге. Команды mkdir и rmdir создают и удаляют каталоги. Эти операции не используются очень часто. Заметим, что команда rmdir не удаляет каталог, если в нем есть еще файлы. 5.4. Команды задач Специально для задач в системе немного команд. Главная из них - это tsk, которая с ее многочисленными параметрами обеспечивает пользователя информацией о работе системы. Вот еще некоторые команды управления задачами: break - вызывает для задачи ситуацию "прервать"; kill - преждевременно завершает задачу; slay - преждевременно завершает задачу по имени. Команда tsk без параметров отображает информацию обо всех задачах, выполняемых в данный момент на узле. Существует три команды для преждевременного завершения задачи, т.е. завершения до ее нормального конца. Команда break - это мягкий способ, так как он только генерирует исключительную ситуацию "прерывание". После этого задача имеет возможность все подчистить и нормально завершиться. Команда kill завершает задачу немедленно, не давая ей шанса все подчистить. В результате все файлы и устройства могут остаться открытыми и в неопределенном состоянии. 27 Команда slay наиболее общая команда по сравнению с первыми двумя. Она и прерывает, и убивает задачу по имени, при этом имеет многочисленные параметры. 5.5. Сетевые команды Существует несколько команд для проверки и управления сетью. Как правило, пользователь редко использует эти команды. Настройка и сопровождение сети - это работа системного администратора. Команда net отображает краткую общую информацию о каждом узле в сети (включая и текущий), а другие две команды взаимодействуют с пользователем. QNX предоставляет две команды для передачи текстовых сообщений (в противоположность межзадачным сообщениям) другим пользователям сети. Команда beep посылает серию коротких сигналов и сообщение (необязательно) другому пользователю или другому узлу. Команда apb, с другой стороны, посылает сообщение к каждой консоли и терминалу на каждом узле системы. Можно получить список пользователей, вошедших в сеанс работы с текущим узлом, используя команду who. 5.6. Печать Существует два способа печати текстовых файлов: путем непосредственного вывода на принтер и путем "спулирования" (накопления) их для совместно используемого принтера. Простейший метод - это перенаправление вывода команды копирования на устройство печати. Хотя это простой способ, но он может быть использован для вывода на печать, если только один пользователь использует принтер в текущий момент, при этом не выполняется деление на страницы, вставка заголовков и т.п. Файл печатается точно в таком же виде, в каком он содержится в файле. В другом случае можно использовать преимущества команды list, которая позволяет форматировать вывод. Заметим, что команда list хорошо ведет себя в многопользовательской среде. Т.е. она будет ожидать завершения предшествующей команды list, прежде чем сама начнет свой вывод. "Накопление" - это более "вежливый" способ печати файлов на одном или нескольких принтерах, которые используются на нескольких узлах. В действительности накопление означает постановку файлов в очередь к заданному устройству. Если в очереди находится несколько файлов, то они будут обрабатываться последовательно в порядке постановки в очередь. 5.7. Файлы инициализации Файл инициализации содержит команды, которые выполняются автоматически, когда загружается узел. QNX поставляется с общей версией этого файла - "sys.init" - которая может быть настроена 28 на конкретную установку. В файл инициализации могут быть помещены команды, которые выполняют конкретную настройку системы; например, электронный диск, совместно используемые библиотеки, виртуальные консоли и т.п. На компьютерах класса AT (80286 или 80386) необходимо выполнять команду rtc для чтения часов реального времени и установки системных часов. 5.8. Управление дисками Хотя управление дисками является функцией другого администратора системы, существует ряд вещей, которые пользователь захочет время от времени выполнять. Особенно, если возникли подозрения на неисправность файла. Файловая система также может стать несогласованной в результате сбоев системы или программы, или в результате побочных эффектов некоторых команд QNX. Пользователь может запросить, например, какой объем памяти уже занят на диске и сколько памяти осталось. 29 ЗАКЛЮЧЕНИЕ Операционная система QNX является мощной операционной системой, позволяющей проектировать сложные программные системы, работающие в реальном времени как на одном единственном компьютере, так и в локальной вычислительной сети. Встроенные средства операционной системы QNX обеспечивают поддержку многозадачного режима на одном компьютере и взаимодействие параллельно выполняемых задач на разных компьютерах, работающих в среде ЛВС. Основыным языком программирования в системе является язык Си, широко используемый в настоящее время на большинстве персональных компютеров. Это позволяет с небольшими доработками перенести необходимое накопленное программное обеспечение в среду операционной системы QNX для организации их работы в среде распределенной обработки.