Интерфейс пользователя
Традиционный способ взаимодействия пользователя с системой UNIX основывается на командных языках. После входа пользователя в систему для него запускается один из командных интерпретаторов (в зависимости от параметров, сохраняемых в файле/etc/passwd). Обычно в системе поддерживается несколько командных . интерпретаторов с похожими, но различающимися своими возможностями командными языками. Общее название для любого командного интерпретатора ОС UNIX — оболочка (shell), поскольку любой интерпретатор представляет внешнее окружение ядра системы. По умолчанию в системах Linux командным интерпретатором является bash. В принципе он может быть заменен другим, но практически никто этого не делает.
Вызванный командный интерпретатор выдает приглашение на ввод пользователем командной строки, которая может содержать простую команду, конвейер команд или последовательность команд. После выполнения очередной командной строки и выдачи на экран терминала или в файл соответствующих результатов интерпретатор команд снова выдает приглашение на ввод командной строки, и так до тех пор, пока пользователь не завершит свой сеанс работы и не выйдет из системы.
Семейство операционных систем 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-системе называют механизм взаимодействия между пользователями и системой. По сути дела, это интерпретатор команд, который считывает набираемые пользователем строки и запускает указанные в командах программы, которые и выполняют запрошенные системные функции и операции. Полный командный язык, интерпретируемый оболочкой, богат возможностями и достаточно сложен, однако большинство команд просты в использовании, и запомнить их не составляет труда.
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____________________________________ 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
Дата добавления: 2016-09-20; просмотров: 937;