Семейство операционных систем UNIX

UNIX является исключительно удачным примером реализации простой мульти­программной и многопользовательской операционной системы. В свое время она проектировалась как инструментальная система для разработки программного обеспечения. Своей уникальностью система UNIX обязана во многом тому обсто­ятельству, что была, по сути, создана всего двумя разработчиками1, которые дела­ли ее исключительно для себя и первое время использовали на мини-ЭВМ с очень скромными вычислительными ресурсами. Первая версия этой системы занимала всего около 12 Кбайт и могла работать на компьютерах с очень небольшим объ­емом оперативной памяти. Поскольку при создании второй версии UNIX разра­ботчики отказались от языка ассемблера и специально придумали язык высокого уровня, на котором можно было бы писать не только системные, но и прикладные программы (речь идет о языке С), то и сама система UNIX, и приложения, выпол­няющиеся в ней, стали легко переносимыми (мобильными). Компилятор с языка С для всех оттранслированных программ дает реентерабельный и разделяемый код, что позволяет эффективно использовать имеющиеся в системе ресурсы.

Общая характеристика

И особенности архитектуры

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

Второй целью была общность. Одни и те же методы и механизмы должны были использоваться во многих случаях:

- обращение к файлам, устройствам ввода-вывода и буферам межпроцессных сообщений выполняются с помощью одних и тех же примитивов;

- одни и те же механизмы именования, присвоения альтернативных имен и за­щиты от несанкционированного доступа применяются и к файлам с данными, и к каталогам, и к устройствам;

- одни и те же механизмы работают в отношении программно и аппаратно ини­циируемых прерываний.

Третья цель заключалась в том, чтобы сложные задачи можно было решать, ком­бинируя существующие небольшие программы, а не разрабатывая их заново.

Наконец, четвертая цель состояла в создании мультитерминальной операционной системы с эффективными механизмами разделения не только процессорного вре­мени, но и всех остальных ресурсов. В мультитерминальной операционной систе­ме на одно из первых мест по значимости выходят вопросы защиты одних вычис-

Семейство операционных систем UNIX - student2.ru ' Создателями системы UNIX считаются Кен Томпсон и Деннис Ритчи. В своей операционной систе­ме Томпсон и Ритчи учли опыт работы над проектом сложной мультизадачной операционной систе­мы с разделением времени, которая имела название MULTICS (MULTiplexed Information and Computing System). Название новой системы UNIX произошло от аббревиатуры UNICS (Uniplexed Information and Computing System).




Семейство операционных систем UNIX - student2.ru Семейство операционных систем UNIX____________________________________ 313

лительных процессов от вмешательства других вычислительных процессов. При­чем для реализации третьей цели необходимо было создать механизмы полноцен­ного обмена данными между программными модулями, из которых предполага­лось составлять конечные программы.

Операционная система UNIX обладает простым, но очень мощным командным языком и независимой от устройств файловой системой. Важным, хотя и простым с позиций реализации такой возможности, является тот факт, что система UNIX предоставляет пользователям средства направления выхода одной программы не­посредственно на вход другой. В результате достигается четвертая цель — большие программные системы можно создавать путем композиции имеющихся небольших программ, а не путем написания новых, что в большинстве случаев упрощает зада­чу. UNIX-системы существуют уже 30 лет, и к настоящему времени имеется чрез­вычайно большой набор легко переносимых из системы в систему отлично отла­женных и проверенных временем приложений.

В число системных и прикладных программ, поставляемых с UNIX-системами, входят редакторы текстов, программируемые интерпретаторы командного языка, компиляторы с нескольких популярных языков программирования, включая С, C++, ассемблер, PERL, FORTRAN и многие другие, компоновщики (редакторы межпрограммных связей), отладчики, многочисленные библиотеки системных и пользовательских программ, средства сортировки и ведения баз данных, много­численные административные и обслуживающие программы. Для абсолютного большинства всех этих программ имеется документация, в том числе исходные тексты программ (как правило, хорошо комментированные). Кроме того, описа­ния и документация по большей части доступны пользователям в интерактивном режиме. Используется иерархическая файловая система с полной защитой, рабо­та со съемными томами, обеспечивается независимость от устройств.

Центральной частью UNIX-систем является ядро (kernel). Оно состоит из боль­шого количества модулей и с точки зрения архитектуры считается монолитным. Однако в ядре всегда можно выделить три основные подсистемы: управления про­цессами, управления файлами, управления операциями ввода-вывода между цен­тральной частью и периферийными устройствами. Подсистема управления про­цессами организует выполнение и диспетчеризацию процессов, их синхронизацию и разнообразное межпроцессное взаимодействие. Важнейшая функция подсисте­мы управления процессами — это распределение оперативной памяти и (для со­временных систем) организация виртуальной памяти. Подсистема управления файлами тесно связана и с подсистемой управления процессами, и с драйверами. Ядро может быть перекомпилировано с учетом конкретного состава устройств компьютера и решаемых задач. Не все драйверы могут быть включены в состав ядра, часть из них может вызываться из ядра. Более того, очень большое количе­ство системных функций выполняется системными программными модулями, не входящими непосредственно в ядро, но вызываемых из ядра. Основные систем­ные функции, которые должно выполнять ядро совместно с остальными систем­ными модулями, строго стандартизированы. За счет этого во многом достигается переносимость кода между разными версиями UNIX и абсолютно различным ап­паратным обеспечением.

Семейство операционных систем UNIX - student2.ru 314________________ Глава 10. Краткий обзор современных операционных систем

Основные понятия

Одним из достоинств ОС UNIX является то, что система базируется на неболь­шом числе понятий; рассмотрим их вкратце. Здесь необходимо отметить, что на­стоящая книга не претендует на полноценное изложение основ работы и детальное описание архитектуры системы UNIX (или Linux). На эту тему имеется достаточ­ное количество специальной литературы, например отличная монография [39] или такие замечательные книги, как [23,43]. Тем не менее, исходя из имеющегося опы­та преподавания предметов, относящихся к операционным системам и системно­му программному обеспечению, считаю полезным изложить здесь минимальный набор основных понятий, который часто помогает студентам «погрузиться в мир UNIX», отличающийся от привычного всем окружения Windows.

Виртуальная машина

Система UNIX многопользовательская. Каждому пользователю после регистра­ции (входа в систему) предоставляется виртуальный компьютер, в котором есть все необходимые ресурсы: процессор (процессорное время выделяется на основе круговой, или карусельной, диспетчеризации и с использованием динамических приоритетов, что позволяет обеспечить равенство в обслуживании), оперативная память, устройства, файлы. Текущее состояние такого виртуального компьютера, предоставляемого пользователю, называется образом. Можно сказать, что про­цесс — это выполнение образа. Образ процесса состоит:

- из образа памяти;

- значений общих регистров процессора;

- состояния открытых файлов;

- текущего каталога файлов;

- другой информации.

Образ процесса во время выполнения процесса размещается в основной памяти. В старых версиях UNIX образ можно было «сбросить» на диск, если какому-либо более приоритетному процессу требовалось место в основной памяти. Напомним, что такое замещение процессов называется свопингом (swapping). В современных реализациях, поддерживающих, как правило, страничный механизм виртуальной памяти, прежде всего выгружаются неиспользуемые страницы, а не целиком об­раз. В частности, в системах Linux свопинг образов не применяется, но создается специальный1 раздел на магнитном диске для файла подкачки (swap-file), где раз­мещаются виртуальные страницы выполняющихся процессов, для которых не хва­тает места в оперативной памяти. Таким образом, замещаются не процессы, а их отдельные страницы.

Образ памяти делится на три логических сегмента:

- сегмент реентерабельных процедур (начинается с нулевого адреса в виртуаль­ном адресном пространстве процесса);

Семейство операционных систем UNIX - student2.ru 1 Сигнатура этого раздела обозначается как 082h.

Семейство операционных систем UNIX - student2.ru Семейство операционных систем UNIX___________________________________ 315

- сегмент данных (располагается следом за сегментом процедур и может расти в сторону больших адресов);

- сегмент стека (начинается со старшего адреса и растет в сторону младших адре­сов по мере занесения в него информации при вызовах подпрограмм и при пре­рываниях).

В современных версиях UNIX-систем все виртуальное адресное пространство каж­дого образа отображается на реальную физическую память компьютера. Исполь­зуется страничный механизм организации виртуальной памяти. И следует разли­чать замещение процессов и подкачку страниц, хотя в обоих случаях используется термин swapping.

Пользователь

Мы уже отмечали, что с самого начала операционная система UNIX замышлялась как интерактивная многопользовательская система. Другими словами, UNIX пред­назначена для мультитерминальной работы. Чтобы начать работать, пользователь должен «войти» в систему, введя со свободного терминала свое учетное, или вход­ное, имя (account name, или login) и пароль (password). Человек, зарегистрирован­ный в учетных файлах системы и, следовательно, имеющий учетное имя, называется зарегистрированным пользователем системы. Регистрацию новых пользователей обычно выполняет администратор системы. Пользователь не может изменить свое учетное имя, но может установить и/или изменить свой пароль. Пароли хранятся в отдельном файле в закодированном виде.

Ядро операционной системы UNIX идентифицирует каждого пользователя по его идентификатору (User Identifier, UID), уникальному целому значению, присваива­емому пользователю при регистрации в системе. Кроме того, каждый пользователь относится к некоторой группе пользователей, которая также идентифицируется не­которым целым значением (Group Identifier, GID). Значения UID и GID для каждого зарегистрированного пользователя сохраняются в учетных файлах системы и при­писываются процессу, в котором выполняется командный интерпретатор, запущен­ный при входе пользователя в систему. Эти значения наследуются каждым новым процессом, запущенным от имени данного пользователя, и используются ядром си­стемы для контроля правомочности доступа к файлам, выполнения программ и т. д.

Все пользователи операционной системы UNIX явно или неявно работают с фай­лами. Файловая система операционной системы UNIX имеет древовидную струк­туру [39]. Промежуточными узлами дерева являются каталоги со ссылками на другие каталоги или файлы, а листья дерева соответствуют файлам или пустым каталогам. Каждому зарегистрированному пользователю соответствует некоторый каталог файловой системы, который называется домашним (home) каталогом поль­зователя. При входе в систему пользователь получает неограниченный доступ к своему домашнему каталогу и всем каталогам и файлам, содержащимся в нем. Пользователь может создавать, удалять и модифицировать каталоги и файлы, со­держащиеся в домашнем каталоге. Потенциально возможен доступ и ко всем дру­гим файлам, однако он может быть ограничен, если пользователь не имеет доста­точных привилегий.

Семейство операционных систем UNIX - student2.ru 316________________ Глава 10. Краткий обзор современных операционных систем

Суперпользователь

Очевидно, что администратор системы, который тоже является зарегистрирован­ным пользователем, чтобы управлять всей системой, должен обладать существен­но большими, чем обычные пользователи, привилегиями. В операционных систе­мах UNIX эта задача решается путем выделения единственного нулевого значения UID. Пользователь с таким значением UID называется суперпользователем (su-peruser) и обозначается словом root (корень). Он имеет неограниченные права на доступ к любому файлу и на выполнение любой программы. Кроме того, такой пользователь имеет возможность полного контроля над системой. Он может оста­новить ее и даже разрушить. По этой причине не рекомендуется работать под этой учетной записью. Администратор должен создать себе обычную учетную запись простого пользователя, а для выполнения действий, связанных с административ­ными полномочиями, рекомендуется использовать команду su. Команда su запра­шивает у пользователя пароль суперпользователя, и, если он указан правильно, операционная система переводит сеанс пользователя в режим работы суперполь­зователя. После выполнения необходимых действий, требующих привилегий су­перпользователя, следует выполнить команду exit, которая и вернет администра­тору статус простого пользователя.

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

Интерфейс пользователя

Традиционный способ взаимодействия пользователя с системой UNIX основыва­ется на командных языках. После входа пользователя в систему для него запуска­ется один из командных интерпретаторов (в зависимости от параметров, сохраня­емых в файле/etc/passwd). Обычно в системе поддерживается несколько командных . интерпретаторов с похожими, но различающимися своими возможностями коман­дными языками. Общее название для любого командного интерпретатора ОС UNIX — оболочка (shell), поскольку любой интерпретатор представляет внешнее окружение ядра системы. По умолчанию в системах Linux командным интерпре­татором является bash. В принципе он может быть заменен другим, но практичес­ки никто этого не делает.

Вызванный командный интерпретатор выдает приглашение на ввод пользовате­лем командной строки, которая может содержать простую команду, конвейер ко­манд или последовательность команд. После выполнения очередной командной строки и выдачи на экран терминала или в файл соответствующих результатов интерпретатор команд снова выдает приглашение на ввод командной строки, и так до тех пор, пока пользователь не завершит свой сеанс работы и не выйдет из си­стемы.

Семейство операционных систем UNIX - student2.ru Семейство операционных систем UNIX____________________________________ 317

Командные языки, используемые в UNIX, достаточно просты, чтобы новые пользо­ватели могли быстро начать работать, и достаточно мощны, чтобы можно было использовать их для написания сложных программ. Последняя возможность опи­рается на механизм командных файлов (shell scripts), которые могут содержать про­извольные последовательности командных строк. При указании имени командно­го файла вместо очередной команды интерпретатор читает файл строка за строкой и последовательно интерпретирует команды.

Поскольку в настоящее время все большее распространение получают графичес­кие интерфейсы, в операционных системах семейства UNIX стали все чаще рабо­тать в X-Window. X-Window — это графический интерфейс, позволяющий пользо­вателям взаимодействовать со своими вычислениями и с системой в графическом режиме. В отличие от систем Windows компании Microsoft, графический интер­фейс для UNIX-систем не является основным, в системе можно работать и без него. Прежде всего, графический режим разрабатывался для приложений, предназна­ченных для работы с графикой. Однако в последние годы его стали применять го­раздо чаще, особенно в системах Linux, которые начинают использовать не только как серверные операционные системы, но и как системы для персональных компь­ютеров.

Графический интерфейс в UNIX-системах основан на модели клиент-сервер. Сер­верная часть X-Window — это аппаратно-зависимая система ввода-вывода, кото­рая непосредственно взаимодействует с приложением и видеоподсистемой, кла­виатурой и мышью. При этом серверная часть должна работать на компьютере, производящем вычисления. Взаимодействие с пользователем осуществляется че­рез клиентскую часть, которая обеспечивает вывод данных на дисплей и прием их с устройств ввода. Клиентская часть должна быть на том компьютере, за которым работает пользователь. Таким образом, можно работать в графическом режиме, сидя за одним компьютером, в то время как собственно вычисления могут проис­ходить и на другом компьютере.

Один из клиентов X-Window — это оконный менеджер (также называемый дис­петчером окон). Он управляет размещением окон на экране, определяет их вид и характер управляющих элементов. То есть именно он и предоставляет пользова­телю графический интерфейс (GUI), тогда как X-Window — это его основа.

В системах Linux наиболее популярными менеджерами графического интерфейса являются KDE и GNOME. Для запуска X-Window в системах семейства UNIX (и Linux) используется команда startx.

Команды и командный интерпретатор

Как уже упоминалось, оболочкой (shell) в UNIX-системе называют механизм вза­имодействия между пользователями и системой. По сути дела, это интерпретатор команд, который считывает набираемые пользователем строки и запускает ука­занные в командах программы, которые и выполняют запрошенные системные функции и операции. Полный командный язык, интерпретируемый оболочкой, богат возможностями и достаточно сложен, однако большинство команд просты в использовании, и запомнить их не составляет труда.

Семейство операционных систем UNIX - student2.ru 318________________ Глава 10. Краткий обзор современных операционных систем

Командная строка состоит из имени команды (а именно имени выполняемого фай­ла), за которым следует список аргументов, разделенных пробелами. Оболочка разбивает командную строку на компоненты. Указанный в команде файл загружа­ется, и ему обеспечивается доступ к заданным в команде аргументам.

Любой командный язык оболочки фактически состоит из трех частей:

- служебных конструкций, позволяющих манипулировать текстовыми строка­ми и строить сложные команды на основе простых команд;

- встроенных команд, выполняемых непосредственно интерпретатором команд­ного языка;

- команд, представляемых отдельными выполняемыми файлами.

В свою очередь, набор команд последнего вида включает стандартные команды (системные утилиты, такие как vi, cc и т. д.) и команды, созданные пользователями системы. Для того чтобы выполняемый файл, разработанный пользователем ОС UNIX, можно было запускать как команду оболочки, достаточно определить в од­ном из исходных файлов функцию с именем main (имя main должно быть глобаль­ным, то есть перед ним не должно указываться ключевое слово static). Если упо­требить в качестве имени команды имя такого выполняемого файла, командный интерпретатор создаст новый процесс и запустит в нем указанную выполняемую программу, начиная с вызова функции main.

Тело функции main, вообще говоря, может быть произвольным (для интерпре­татора существенно только наличие входной точки в программу с именем main), но для того чтобы создать команду, которой можно задавать параметры, при­держиваются некоторых стандартных правил. В этом случае каждая функция main должна определяться с двумя параметрами — argc и argv. После вызова команды параметру argc будет соответствовать число символьных строк, ука­занных в качестве аргументов вызова команды, a argv — массив указателей на переменные, содержащие эти строки. При этом имя самой команды составляет первую строку аргументов (то есть после вызова значение argc всегда больше или равно 1). Код функции main должен проанализировать допустимость за­данного значения argc и соответствующим образом обработать заданные тек­стовые строки.

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

#iinclude <stdio.h> main (argc. argv) int argc; char *argv[]:

{

if (argc != 2) { printf("usage: %s your-text\n". argv[O]);

exit:

} printf("%s\n". argv[l]);

}

Семейство операционных систем UNIX - student2.ru Семейство операционных систем UNIX____________________________________ 319

Процессы

Процесс в системах UNIX — это процесс в классическом понимании этого термина, то есть это программа, выполняемая в собственном виртуальном адресном простран­стве. Когда пользователь входит в систему, автоматически создается процесс, в ко­тором выполняется программа командного интерпретатора. Если командному ин­терпретатору встречается команда, соответствующая выполняемому файлу, то он создает новый процесс и запускает в нем соответствующую программу, начиная с функции main. Эта запущенная программа, в свою очередь, может создать процесс и запустить в нем другую программу (та тоже должна содержать функцию main) и т. д.

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

Другими словами, сразу после выполнения системного вызова fork() основной (ро­дительский) и порожденный процессы являются абсолютными близнецами; управ­ление в том и другом находится в точке, непосредственно следующей за вызовом fork(). Чтобы программа могла разобраться, в каком процессе (основном или по­рожденном) она теперь работает, функция fork() возвращает разные значения: О в порожденном процессе и целое положительное число в основном процессе. Этим целым положительным числом является уже упоминавшийся идентификатор про­цесса (PID). Таким образом, родительский процесс будет знать идентификатор своего дочернего процесса и может при необходимости управлять им.

Теперь, если мы хотим запустить новую программу в порожденном процессе, нуж­но обратиться к системному вызову exec, указав в качестве аргументов вызова имя файла, содержащего новую выполняемую программу, и, возможно, одну или не­сколько текстовых строк, которые будут переданы в качестве аргументов функ­ции main новой программы. Выполнение системного вызова exec приводит к тому, что в адресное пространство порожденного процесса загружается новая выполня­емая программа и запускается с адреса, соответствующего входу в функцию main. Другими словами, это приводит к замене текущего программного сегмента и теку­щего сегмента данных, которые были унаследованы при выполнении вызова fork, соответствующими сегментами, заданными в файле. Прежние сегменты теряются. Это эффективный метод смены выполняемой процессом программы, но не самого процесса. Файлы, уже открытые до вызова примитива exec, остаются открытыми после его выполнения.

В следующем примере пользовательская программа, вызываемая как команда обо­лочки, выполняет в отдельном процессе стандартную команду Is оболочки, кото­рая выдает на экран содержимое текущего каталога.

main()

{if(fork()==0) wait(O); /* родительский процесс */ else execlC'ls". "Is". 0): /* порожденный процесс */ }

320________________ Глава 10. Краткий обзор современных операционных систем

Таким образом, с практической точки зрения процесс в UNIX является объектом, создаваемым в результате выполнения функции fork().Каждый процесс за исклю­чением начального (нулевого) порождается в результате вызова другим процес­сом функции fork(). Каждый процесс имеет одного родителя, но может породить много процессов. Начальный (нулевой) процесс является особенным процессом, который создается в результате загрузки системы. После порождения нового про­цесса с идентификатором 1 нулевой процесс становится процессом подкачки и реализует механизм виртуальной памяти. Процесс с идентификатором 1, извест­ный под именем init, является предком любого другого процесса в системе и свя­зан с каждым процессом особым образом.

Функционирование

Теперь, когда мы познакомились с основными понятиями, рассмотрим наиболее характерные моменты функционирования UNIX-системы.

Выполнение процессов

Процесс может выполняться в одном из двух состояний, а именно пользователь­ском и системном. В пользовательском состоянии процесс выполняет пользова­тельскую программу и имеет доступ к пользовательскому сегменту данных. В сис­темном состоянии процесс выполняет программы ядра и имеет доступ к системному сегменту данных.

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

В UNIX-системах организуется разделение времени (time sharing), то есть каждо­му процессу выделяется квант времени. Либо процесс завершается сам до истече­ния отведенного ему кванта времени, либо он приостанавливается по истечении кванта и продолжает свое исполнение при очередном получении нового кванта времени. Механизм диспетчеризации характеризуется достаточно справедливым распределением процессорного времени между всеми процессами. Пользователь­ским процессам приписываются приоритеты в зависимости от получаемого ими процессорного времени. Процессам, которые получили много процессорного вре­мени, назначают более низкие приоритеты, в то время как процессам, которые по­лучили лишь немного процессорного времени, наоборот, повышают приоритет. Вспомните рассмотренные ранее механизмы динамических приоритетов. Такой метод диспетчеризации обеспечивает хорошее время реакции для всех пользова­телей системы. Все системные процессы имеют более высокие приоритеты по срав­нению с пользовательскими и поэтому всегда обслуживаются в первую очередь.

Семейство операционных систем UNIX____________________________________ 321

Подсистема ввода-вывода

Функции ввода-вывода в UNIX задаются в основном с помощью пяти системных вызовов: open, close, read, write и seek.

Открыть файл можно следующей командой:

file_descriptor = open (filejiame. mode)

Здесь mode — режим открытия файла (чтение, запись или то и другое); file_de-scriptor — дескриптор файла, служит для последующих ссылок на данный файл; file_name — имя открываемого файла. Чтение и запись осуществляются командами следующего вида:

after_reading_bytes - read (file_descriptor. buffer, bytes) after_writing_bytes = write (file_descriptor. buffer, bytes)

Здесь bytes — количество байтов, которые должны быть прочитаны или записаны; after_reading_bytes и after_writing_bytes — реально прочитанное и записанное коли­чество байтов соответственно.

При чтении возможны три ситуации, в каждой из которых чтение происходит по­следовательно:

- если это первое чтение из файла, то оно осуществляется последовательно с са­мого начала файла;

- если операции чтения предшествовала другая операция чтения из этого файла, то текущая операция предоставит данные, непосредственно следующие за пре­дыдущими;

- если предшествовала операция поиска seek (см. далее), то чтение осуществля­ется последовательно от точки смещения, указанной в операции seek.

Это же справедливо и по отношению к операции записи в файл. Обратите внима­ние, что все эти вызовы относятся к последовательному доступу и эффект прямой адресации достигается с помощью команды seek, смещающей текущую позицию файла:

Seek (fi1e_descriptor.di splacement.di splacement_type)

Здесь параметр displacement_type (тип смещения) определяет, является смещение абсолютным или относительным, а также задано оно числом байтов или числом блоков по 512 байт.

Важно заметить, что команда seek исполняется для магнитных дисков так же, как и для магнитных лент, которые нынче уже практически не используются, но во времена появления и становления UNIX-систем были часто используемым уст­ройством.

Чтобы закрыть файл, достаточно выполнить следующую команду:

close (file_descriptor)

Еще три примитива — gtty, stty, stat — позволяют получать и задавать информа­цию о файлах и терминалах.

Те же самые команды ввода-вывода применяются и к физическим устройствам. В UNIX-системах физические устройства представлены специальными файлами в единой структуре файловой системы. Это означает, что пользователь не может

Семейство операционных систем UNIX - student2.ru 322________________ Глава 10. Краткий обзор современных операционных систем

написать зависящую от устройств программу, если только эта зависимость не от­ражена в самом потоке передаваемых данных. Стандартные файлы ввода и выво­да, приписываемые пользовательскому терминалу, открывать обычным путем не требуется. Терминал открывается автоматически по команде входа в систему login.

Система ввода-вывода UNIX в отличие от большинства других систем ориентиро­вана на работу скорее с потоком данных, а не с записями. Здесь поток данных (stream)1 — это последовательность байтов, заканчивающаяся разделителем (то есть символом конца потока). Понятие потока данных позволяет проще добиться неза­висимости от устройств и унификации файлов с физическими устройствами и кон­вейерами. Тем самым пользователь получает гибкость в работе с группами дан­ных, но на него ложатся и дополнительные заботы, поскольку ему приходится писать программы управления данными. Пользователь может при необходимости относительно легко самостоятельно реализовать работу с записями. Чтобы рабо­тать с записями фиксированной длины, достаточно просто задавать постоянную длину во всех командах чтения и записи. Для нахождения позиции нужной записи при фиксированной длине записей нужно умножить длину записи на помер запи­си и выполнить команду seek. Работу с записями переменной длины можно орга­низовать, если разместить в начале каждой записи поле фиксированного размера, содержащее значение длины записи.

Наши рекомендации