Индекс
НазадОглавлениеВперед


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

До сих пор мы рассматривали взаимодействие с ОС, выполняемое из программы при помощи вызовов API - интерфейса прикладного программиста. Теперь рассмотрим взаимодействие вне программы - через команды, вводимые с клавиатуры терминала в интерактивных системах или поступающие во вводном потоке в пакетных системах. В первом случае, как правило, новая команда вводится после выполнения предыдущей, и сама новая команда или ее параметры могут выбираться в зависимости от результатов этого выполнения. Во втором случае задается сразу целая последовательность команд, и возможные отклонения от последовательного их выполнения должны задаваться явным образом. Из таких различий в технологии взаимодействия пользователей с системой вытекают естественные различия в интерактивных и пакетных командных языках, но по мере расширения командных языков они имеют тенденцию к сближению: в интерактивные командные языки включаются возможности задания последовательностей команд, а в пакетные - более гибкие средства управления последовательностью выполнения.

11.1. Командный язык и командный процессор

Команды представляют собой инструкции, сообщающие ОС, что нужно делать. Команды могут восприниматься и выполняться либо модулями ядра ОС, либо отдельным процессом, в последнем случае такой процесс называется командным интерпретатором (оболочкой - shell). Набор допустимых команд ОС и правил их записи образует командный язык (CL - control language).

Большинство запросов пользователя к ОС состоят из двух компонент, показывающих: какую операцию следует выполнить и в каком окружении (environment) должно происходить выполнение операции. Могут различаться внутренние и внешние операции-команды. Выполнение внутренних операций производится самим командным интерпретатором, выполнение внешних требует вызова программ-утилит. Наличие в составе командного языка внутренних команд представляется совершенно необходимым для тех случаев, когда командный интерпретатор является отдельным процессом. Среди команд имеются такие, в которых выполняются системные вызовы, изменяющие состояние самого командного интерпретатора, если для них интерпретатор будет создавать новые процессы, то изменяться будет состояние нового процесса, а не интерпретатора. Примеры таких команд: chdir - изменение рабочего каталога для интерпретатора, wait - интерпретатор должен ждать завершения порожденного им процесса и т.п. Программы-утилиты (их загрузочные модули) записаны в файлах на внешней памяти. При их вызове порождаются процессы, и утилиты выполняются в контексте этих процессов. Вызов и выполнение программ-утилит ничем не отличаются от вызова и выполнения приложений. Командный интерпретатор порождает процессы-потомки и выполняет в них заданные программы, используя для этого те же самые системные вызовы, которые мы рассмотрели в главе 4. Задание операции в командном языке, таким образом, может иметь вид имени программного файла, который должен быть выполнен.

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

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

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

Команды для установки локальных параметров окружения применяются обычно в системах, работающих в пакетном режиме. В таких системах основным понятием является задание - единица работы с точки зрения пользователя. Выполнение задания состоит из одного или нескольких шагов. Каждый шаг задания включает в себя оператор JCL (job control language - язык управления заданиями) вызова программы и операторов установки локальной среды. Интерпретатор JCL сначала вводит все операторы, относящиеся к шагу задания, и лишь затем их выполняет. Тот же способ может применяться и в интерактивных системах - в этом случае команды установки параметров локальной среды должны предшествовать команде вызова.

Параметры программы также задают локальную среду выполнения. Они являются дополнениями к команде вызова, вводятся в той же командной строке, что и команда вызова, или являются параметрами оператора вызова в JCL. Формы задания параметров можно, по-видимому, свести к трем вариантам: позиционные, ключевые и флаговые. Возможны также и их комбинации. Позиционная форма передачи параметров программе похожа на общепринятую форму передачи параметров процедурам: параметры передаются в виде списка значений, интерпретация значения зависит от его места в списке. При передаче параметров в ключевой форме задается обозначение (имя) параметра и его значение; имя от значения отделяется специфицированным разделителем. Иногда другой специфицированный разделитель ставится перед именем как признак ключевой формы. Флаговая форма применяется для параметров, которые могут иметь только логические значения типа "да"/"нет"; такой параметр обычно кодируется одним определенным для него символом, иногда перед ним ставится специфицированный разделитель. Для флагового параметра информативным является само его задание в команде вызова: если параметр не задан, применяется его значение по умолчанию, если задан - противоположное значение.

Ниже приводятся примеры передачи параметров:

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

Каким образом параметры могут быть переданы программе? Можно назвать такие возможные механизмы передачи параметров:

В языках программирования, однако, механизм передачи параметров прозрачен для программиста, доступ к параметрам обеспечивает компилятор и в любом случае программа получает значения параметров уже в своем адресном пространстве. Так, в языке C для главной функции программы предопределен прототип::

    int main(int argn, char *argv[]); 

где argn - число строк-параметров, argv - указатель на массив строк-параметров.

Для установки глобального окружения применяются команды типа set. Операндами такой команды могут быть символьные строки, задающие в ключевой форме значения параметров окружения. Например:

    set tempdir=d:\util\tmp
    set listmode=NO, BLKSIZE=1024

Переменные окружения могут быть системными или пользовательскими. Системные имеют зарезервированные символьные имена и интерпретируются командным интерпретатором либо другими системными утилитами. Например, типичной является системная переменная окружения path, значение которой задает список каталогов для поиска программ командным интерпретатором. Пользовательские переменные создаются, изменяются и интерпретируются пользователями и приложениями. Чтобы окружение могло быть использовано, в системе должны быть средства доступа к нему. На уровне команд - это должна быть команда типа show, выводящая на терминал имена и значения всех переменных глобального окружения, на уровне API - системный вызов getEvironment, возвращающий адрес блока глобального окружения.

Для внутреннего представления глобального окружения в ОС возможны два варианта: либо хранить в системе единую таблицу со значениями всех переменных окружения, либо для каждого процесса создавать собственную копию такой таблицы. Чаще используется второй вариант, который обеспечивает, во-первых, лучшую защиту глобального окружения, а во-вторых, возможность варьировать окружения для разных процессов, используя глобальное окружение отчасти как локальное. Очень удобным является этот вариант для систем с иерархической структурой отношений между процессами: в этом случае глобальное окружение является частью наследства, передаваемого от предка к потомку. Системные вызовы, связанные с порождением новых процессов, должны обеспечивать возможность передавать потомку как точную копию глобального окружения родителя, так и оригинальное окружение, специально созданное родителем для потомка.

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

В ОС, применяющих "философию дешевых процессов", (см. главу 4), предполагается выполнение сложных действий как результата совместной (последовательной или параллельной) работы нескольких простых процессов. Поэтому командный язык должен включать в себя средства интеграции процессов. К числу таких средств относятся:

Командные списки представляют собой простое перечисление в одной командной строке нескольких команд. Например, результат выполнения такой командной строки:

    pgm1 param11 param12; pgm2; pgm3 param31 

будет таким же, как при последовательным выполнении трех строк:

    pgm1 param11 param12
    pgm2
    pgm3 param31

Командные списки представляют более удобную форму, но не открывают никаких новых возможностей.

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

    pgm1 < infile
    pgm2 > outfile

Соединение командного списка с переадресацией ввода-вывода обеспечивает конвейеризацию. В примере:

    pgm1 param11 param12 | pgm2 | pgm3 param31 

выходные данные программы pgm1 направляются не на экран, а сохраняются и затем используются, как входные для программы pgm2. Выходные данные последней в свою очередь используются как входные для pgm3.

В ОС с "философией дешевых процессов" допускается параллельное выполнение любого количества процессов. В обычном режиме командный интерпретатор готов к приему следующей команды только после окончания выполнения предыдущей. Специальная команда запуска программы или какой-либо признак в командной строке (например, символ-амперсанд в конце ее) может применяться в качестве указания командному процессору вводить и выполнять следующую команду, не дожидаясь окончания выполнения предыдущей. Так, последовательность командных строк:

    pgm1 param11 param12 &
    pgm2 &
    pgm3 param31 

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

Ниже приведен программный текст, представляющий в значительно упрощенном виде макет командного интерпретатора shell ОС Unix (синтаксис и семантика системных вызовов в основном тоже соответствуют этой ОС). Из этого примера можно судить о том, как shell реализует некоторые из описанных выше возможностей.

     1   int fd, fds [2]; 
     2   int status, retid, numchars=256; 
     3   char buffer [numchars], outfile[80]; 
     4   . . . 
     5   while( read(stdin,buffer,numchars) ) { 
     6     <синтаксический разбор командной строки>
     7     if (<не внутренняя команда>) { 
     8      if(<командная строка содержит &>) amp=1; 
     9       else amp=0; 
    10       if( fork() == 0 ) { 
    11         if( < переадресация вывода > ) { 
    12           fd = create(outfile,<режим>); 
    13           close(stdout); 
    14           dup(fd); 
    15           close(fd); 
    16         }
    17         if(<переадресация ввода>) {
    18           <подобным же образом> 
    19         } 
    20         if(<конвейер>) { 
    21           pipe (fds); 
    22           if ( fork() == 0 ) { 
    23             close(stdin); 
    24             dup(fds[0]); 
    25             close(fds[0]);
    26             close(fds[1]); 
    27             exec(pgm2, <параметры> ); 
    28           }
    29           else { 
    30             close(stdout); 
    31             dup(fds[1]); 
    32             close(ds[1]); 
    33             close(fds[0]); 
    34           }
    35         }
    36         exec(pgm1, <параметры>); 
    37       } 
    38       if ( amp == 0 ) retid = wait(&status); 
    39     } 
    40   } 
    41   . . .

Наш макет рассчитан на интерпретацию командной строки, содержащей либо вызов одной программы (pgm1), либо конвейер из двух программ (pgm1|pgm2). Макет также обрабатывает переадресацию ввода-вывода и параллельное выполнение.

Тело shell представляет собой цикл (5 - 39), в каждой итерации которого из файла стандартного ввода вводится (5) строка символов - командная строка. Далее shell выполняет разбор командной строки, выделяя и распознавая собственно команду (или команды), параметры и т.д. Если (7) распознанная команда не является внутренней командой shell (обработку внутренних команд мы не рассматриваем), а требует выполнения какой-то программы - безразлично, системной утилиты или приложения - то shell проверяет наличие в командной строке признака параллельности и соответственно устанавливает значение флага amp (8, 9). Затем shell порождает новый процесс (10) и весь следующий блок (11 - 37) выполняется только в процессе-потомке. Если shell распознал в команде переадресацию системного вывода (11), то выполняются соответствующие действия (11 - 16). Они состоят в том, что shell создает файл, в который будет перенаправлен поток вывода и получает его манипулятор (12). Затем закрывается файл системного вывода (13). Системный вызов dup (14) дублирует манипулятор fd в первый свободный манипулятор таблицы файлов процесса. Поскольку только что освободился файл системного вывода, манипулятор которого - 1, дублирование произойдет именно в него. Теперь два элемента таблицы файлов процесса - элемент с номером 1 и элемент с номером fd адресуют один и тот же файловый дескриптор - дескриптор только что созданного файла. Но элемент fd сразу же освобождается (15), и теперь только манипулятор 1, который интерпретируется в программе как манипулятор системного вывода, адресует новый файл. Мы предлагаем читателю самостоятельно запрограммировать действия shell при переадресации ввода (17-19). (Для справки: манипулятор системного ввода - 0.)

Если в командной строке задан конвейер (20), то процесс-потомок прежде всего создает канал (21). Параметром системного вызова pipe является массив из двух элементов, в который этот вызов помещает манипуляторы канала: fds[0] - для чтения и fds[1] - для записи. Затем процесс-потомок порождает еще один процесс (22). Следующий блок (23 - 27) выполняется только во втором процессе-потомке. Этот потомок переадресует свой стандартный ввод на манипулятор чтения канала (23 - 25). Манипулятор записи канала освобождается за ненадобностью (26). Затем второй потомок загружается программой, являющейся вторым компонентом конвейера (27). Следующий блок (28 - 34) выполняется только в первом потомке: он переадресует свой стандартный вывод на манипулятор записи канала и освобождает манипулятор чтения канала.

Системный вызов exec (36) выполняется в первом потомке (он является единственным, если конвейер не задан), процесс загружается программой, являющейся первым компонентом конвейера или единственным компонентом командной строки. Обратите внимание на то, что из функции exec нет возврата. При ее вызове выполняется новая программа, с завершением которой завершается и процесс. Процесс-родитель, который все время сохраняет контекст интерпретатора shell, после запуска потомка проверяет (38) флаг параллельного выполнения amp. Если этот флаг не установлен, то родитель выполняет вызов wait, блокирующий shell до завершения потомка. (Этот вызов возвращает идентификатор закончившегося процесса, а в параметре - код завершения, но в нашем макете эти результаты не обрабатываются). Если флаг параллельности установлен, то shell начинает следующую свою итерацию, не дожидаясь завершения потомка.

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

В тех ОС, где командный интерпретатор является процессом, имеется возможность запуска вторичного интерпретатора. Эта возможность является очень удобной, если при работе в среде какого-либо приложения возникает необходимость выполнить команды ОС, но завершать приложение из-за этого нежелательно. Приложение является процессом-потомком командного интерпретатора. Оно порождает новый процесс (потомок приложения), в котором запускается еще одна копия интерпретатора, как показано на Рисунке 11.1. (Новый процесс-интерпретатор может разделять сегмент кодов с первичным интерпретатором). Теперь весь ввод в командную строку обрабатывается этим вторичным интерпретатором. Вторичный интерпретатор может запустить другое приложение и т.д. Вторичный интерпретатор запускается в синхронном режиме, и при его завершении (команда exit) продолжает работать запускавшее его приложение.


Рис.11.1. Запуск вторичного командного интерпретатора

11.2. Командные файлы и язык процедур

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

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

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

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

Параметры и условия являются тем набором средств, который обеспечивает минимальный необходимый сервис. Некоторые ОС на этом и останавливаются. Другие же идут дальше. "Пионером" в этой области (как и во многих других) является ОС Unix. Это неудивительно, так как Unix воплощает "философию дешевых процессов", а для того, чтобы скомпоновать из "дешевых" процессов сложные действия, нужны развитые средства интеграции. Просматривая публикации по ОС Unix в хронологическом порядке, можно наблюдать, как языковые средства shell наращивались новыми алгоритмическими возможностями, все более приближая его к процедурному языку программирования. В итоге shell обладает полным набором средств процедурного программирования (операций и операторов), включая манипулирование с переменными shell-программы, условный оператор, оператор множественного выбора, операторы циклов, оператор обработки исключительных ситуаций, а также возможность создания и вызова функций.

По иному пути пошла фирма IBM, в середине 80-х годов представившая в составе ОС CMS (гостевой ОС в среде ОС виртуальных машин VM/370) реструктурированный расширенный язык процедур - REXX (Restructured EXtended eXecutor language) [31]. Разработчики этого языка пошли не по пути наращивания командного языка алгоритмическими возможностями, а по пути включения в мощный алгоритмический язык (за основу был взят язык PL/1) средств выполнения команд. Подход оказался настолько продуктивным, что за прошедшее с тех пор время REXX практически не претерпел изменений и сейчас входит в базовый комплект поставки не только CMS VM/ESA, но всех ОС фирмы. Наряду со средствами процедурного программирования, "унаследованными" от PL/1 в REXX включен в качестве базовых операций языка ряд операций расширенной обработки строк и большое количество встроенных функций, также прежде всего связанных с обработкой строк, которыми компенсируется отсутствие того богатого набора утилит, который имеется в Unix. Кроме того, в REXX имеется возможности (эти возможности системно-зависимые) работы с текстовыми файлами и обмена данными через очереди или перенаправление ввода-вывода не только в файлы, но и в буферы, подобные программным каналам - pipe, но со структурой дека (очереди с двумя концами). Вообще область применения REXX шире, чем только применение его в качестве командного интерпретатора ОС. Целый ряд продуктов системного и промежуточного программного обеспечения IBM использует REXX как интерпретатор своих команд. Оператор ADDRESS задает имя программы-среды, в которую передается команда.

Оба типа развитых командных языков наряду с одинаковыми алгоритмическими возможностями обладают также еще одним принципиально важным общим свойством - они являются языками интерпретирующего типа. Командный файл REXX или sell не требует компиляции. Эта означает, что полный анализ такого файла не производится (или производится только в первом приближении), и интерпретатор выполняет его команда за командой, "не заглядывая" вперед. Переменные командного файла имеют единственный тип - "строка символов" и основные манипуляции над ними представляют собой строковые операции. При выполнении арифметики строковые данные прозрачно преобразуются в числовые, а результат операции вновь преобразуется в строку. При выполнении каждого очередного оператора командного файла производится подстановка вместо переменных shell- или REXX-программы их значений. В обоих языках предусмотрены средства "экранирования", защищающие строковые литералы от интерпретации их как переменных. Строка, полученная после выполнения подстановки, интерпретируется как оператор командного языка или - если это невозможно - как команда ОС (или другой целевой среды). В REXX имеется возможность даже сформировать символьную строку в переменной REXX-программы, а затем выполнить ее как оператор языка.

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

11.3. Проблема идентификации адресата

При параллельном выполнении нескольких процессов возникает проблема взаимодействия пользователя с ними: при появлении на экране сообщения, как пользователь определит, какой из процессов это сообщение выдал? при вводе сообщения пользователем, как ОС определит, какому процессу сообщение адресовано?. Решение этой проблемы зависит прежде всего от степени интерактивности процессов (насколько часто они обмениваются сообщениями с пользователем). Если процессы не очень интерактивны, то им можно разрешить квазиодновременный вывод на терминал: их сообщения могут чередоваться, но каждое сообщение должно быть неделимым. В этом случае выводимое сообщение должно нести в себе и идентификацию процесса, его выдавшего. Дейкстра [7] подробно рассмотрел реализацию диалогового взаимодействия такого рода с помощью семафоров. Им показано, что для этого случая ответы пользователя должны либо также содержать идентификатор процесса-адресата, либо пара действий вопрос-ответ должна быть одной транзакцией. В последнем случае, однако, задержка ответа надолго блокирует общий канал обмена между процессами и пользователем, поэтому у пользователя также должна быть возможность откладывания ответа с последующим возвращением к диалогу с этим же процессом.

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

Что делать с фоновым процессом, если у него возникла необходимость выдать сообщение на терминал? Одним из решений может быть блокировка такого процесса до его выдвижения. Более эффективным является "скрытый" вывод, при котором обеспечивается для выполнения процессов несколько параллельных сеансов. В каждом сеансе могут выполняться один или несколько процессов. С каждым сеансом связан собственный буфер логического терминала, включающий в себя логический видеобуфер, логический буфер клавиатуры и логический буфер мыши. Весь обмен процесс ведет с логическим видеобуфером терминала. В каждый момент логический буфер только одного (так называемого, активного) сеанса связан с физическими буферами терминальных устройств. Таким образом, фоновый сеанс может вести обмен с терминалом (в основном - вывод) без отображения на терминал. Когда сеанс становится активным, его логический буфер связывается с физическими устройствами, и на экране видеотерминала отображается содержимое его логического видеобуфера. В составе API есть также средства аварийной активизации сеанса: если процессу, работающему в фоновом сеансе, необходимо выдать срочное сообщение, то он может воспользоваться так называемым "иллюминатором". На время существования иллюминатора ОС выделяет временный активный видеобуфер и все средства обмена с консолью работают с этим буфером. Это очень сильное средство, используемое только в исключительных случаях, так как на время существования иллюминатора блокируются запросы активного сеанса, а переключать сеансы в это время не может даже оператор.

11.4. WIMP-интерфейс

Интерфейс командной строки (но не командные файлы!) на сегодняшний день уже можно считать отходящим в прошлое, хотя прогнозировать его окончательный уход мы не беремся. Программируемые видеотерминалы дают возможность выводить информацию в любую позицию экрана и, следовательно, использовать все пространство экрана для организации взаимодействия между ОС и пользователем. Современные интерфейсы как приложений, так и ОС можно охарактеризовать как полноэкранные, графические, объекно-ориентированные.

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

Панель - это информация, определенным образом сгруппированная и расположенная на экране. Основные типы панелей:

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

Панели могут располагаться в отдельных ограниченных частях экрана, называемых окнами. Окна могут быть трех типов:

Общие принципы панельного интерфейса в основном не зависят от типа применяемых терминалов. Однако, сочетание графических видеоадаптеров с высокой разрешающей способностью с общим увеличением вычислительной мощности (быстродействие и объем памяти) персональных вычислительных систем позволяет существенно изменить общий облик экрана. Можно определить следующие основные направления этих изменений: многооконность, целеуказание, иконика. Такие интерфейсы получили название WIMP (Windows, Icons, Menus, Pointer). Первое воплощение идеи WIMP нашли в разработках фирмы Xerox, а первая их коммерчески успешная реализация состоялась в компьютерах Apple Macintosh в 1985 году. Позднее идеи WIMP были приняты в Microsoft Windows, а сейчас они воплощены практически в всех операционных системах.

Интерфейс WIMP обладает концептуальной целостностью, достигаемой принятием знакомой идеальной модели - метафоры рабочего стола - ровной поверхности, на которой расположены объекты и папки, и ее тщательного, последовательного развития для использования воплощения в компьютерной графике. Главное изменение в облике интерфейса - иконика - представление объектов в виде миниатюрных графических изображений - пиктограмм. Помимо чисто внешних изменений иконика породила возможность манипулировать объектами через манипулирование их изображениями. Документы, папки и мусорная корзина являются точными аналогами предметов на столе. Вырезание, копирование и вставка точно имитируют операции, которые обычно осуществляются с документами на столе. Транспортировка непосредственно вытекает из метафоры рабочего стола; выбор значков или окон с помощью курсора является прямой аналогией захвата предметов рукой. Из метафоры рабочего стола непосредственно следует решение о перекрытии окон вместо расположения их одно рядом с другим. Представление активного окна как документа, "лежащего сверху", интуитивно понятным образом решает проблему идентификации адресата. Возможность менять размер и форму окон не имеет прямой аналогии с бумажными документами, но является последовательным расширением, дающим пользователю новые возможности, обеспечиваемые компьютерной графикой

В некоторых случаях интерфейс WIMP отходит от метафоры рабочего стола. Основные отличия: меню и работа одной рукой. Меню представляет собой не совершение действия, а выдачу кому-то (системе) команды на осуществление действия, причем, команда эта не формулируется языковыми средствами, а выбирается из списка.

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

Высокая разрешающая способность графических дисплеев позволяет также имитировать объемные панели, создавая на плоском экране иллюзию светотеней. На "объемной" панели применяются графические элементы - органы управления, такие как: кнопки, линейка протяжки и т.д. Общепринятым является представление полей ввода в "утопленном" виде, а органов управления - в "приподнятом". К настоящему времени облик объемного интерфейса в современных ОС сформировался почти окончательно и включает в себя единый "источник света" и однотипное расположение органов управления на всех панелях.

Объектно-ориентированные свойства интерфейса совершенно необязательно связаны с объектно-ориентированной структурой ОС. Так, например, OS/400 является объектно-ориентированной системой с объектно-ориентированным интерфейсом, Windows NT v.3.51 была объектно-ориентированной ОС без объектно-ориентированного интерфейса, OS/2 и Windows 9x - не объектно-ориентированные ОС с объектно-ориентированным интерфейсом. Объектно-ориентированный интерфейс обычно связывают с графическим интерфейсом, но это необязательно. Так, в той же OS/400 предусмотрены две модели интерфейса: текстовая и графическая, обе в полной мере объектно-ориентированные.

В противовес обычному интерфейсу, который представляет пользователю практически единственный тип объекта - файл, единицу хранения информации в ОС, объектно-ориентированный интерфейс представляет объекты различных типов. Файлы могут быть разными типами объектов - в зависимости от типа информации в них хранящейся и способов ее обработки. Кроме того, объектами могут быть устройства, сетевые ресурсы и т.д. В объектно-ориентированном программировании под объектом понимается абстрактный тип данных, включающий в себя как сами данные, так и процедуры их обработки. Аналогично объекты понимаются и в объектно-ориентированном интерфейсе. Объект обязательно обладает некоторым набором свойств, и значения этих свойств доступно пользователю. Среди свойств, присущих объекту, имеется и указание на способ его обработки - в том числе и на приложение, обрабатывающее данные этого типа. Выполнение некоторых действий над объектом включает в себя автоматический запуск приложений, которые эти действия выполняют.

Концептуально важным объектом интерфейса является папка (folder). Папка - это контейнерный объект, содержащий в себе другие объекты и папки. Уместность папки в метафоре рабочего стола очевидна. Существенно то, что папка дает возможность пользователю создавать собственную структуру хранения объектов, альтернативную структуре хранения объектов в ОС (в файловой системе). Важным свойством, обеспечивающим эту возможность, является создание указателей на объекты. Если папка является физическим аналогом каталога файловой системы, то в нее может быть помещен указатель на объект, физически расположенный в другой папке-каталоге файловой системы (аналог косвенных файлов). Ссылка на объект с точки зрения пользователя выглядит так же, как оригинал объекта (хотя может иметь какие-то отличительные признаки ссылки), выполнение операции открытия над ссылкой приводит к открытию объекта-оригинала, но операции перемещения, удаления, переименования и т.п. выполняются не над объектом, а только над ссылкой. Возникает, однако, проблема согласования интерфейсной структуры хранения объектов с логической структурой файловой системы. Например, требуется, чтобы при перемещении объекта-оригинала в файловой системе все ссылки на него перенаправлялись на новое его место. Не все интерфейсы ОС успешно справляются с этой задачей.

Важным аспектом объектной ориентации является настройка интерфейса для конкретного пользователя. Обычно, если интерфейс рассматривается с точки зрения приложений, отмечается полезность создания нескольких форм интерфейса, ориентированных на пользователя разной квалификации - новичка, опытного, профессионала. Хотя та же задача может ставиться и перед интерфейсом ОС, более важной, на наш взгляд является интеграция интерфейса с системой безопасности ОС. Интерфейс должен показывать пользователю только те объекты и предоставлять ему только те команды, к которым данный пользователь имеет доступ. Такое возможно в тех ОС, где система безопасности тесно связана с объектно-ориентированными свойствами ОС. Настройки интерфейса могут являться частью профиля пользователя.

Каково место интерфейса WIMP в ОС? Можно назвать три подхода к выбору такого места.

Графический интерфейс может встраиваться в саму ОС и быть ее неотъемлемой частью. Такой подход применяется во всех продуктах семейства Windows и в ОС компьютеров Apple (в последних WIMP даже встроен в ПЗУ компьютера). Такой подход дает возможность тесно интегрировать интерфейс с ОС и повысить производительность интерфейсных модулей, выполняя часть из них в режиме ядра. Однако такой подход в то же время является неэкономным, так как интерфейс WIMP расходует много ресурсов и до некоторой степени опасным, так как модули WIMP могут явиться дополнительным источником ошибок в системе.

Графический интерфейс может представлять собой отдельное приложение, поставляемое в составе операционной системы и, возможно, достаточно тесно интегрированное с ней. Пример такого приложения - Workplace Shell OS/2. Такое приложение не допускается в режим ядра, но может использовать API более низкого уровня, чем обычно используемый в приложениях. Такое приложение WIMP не является обязательным компонентом ОС, система может работать и без него, в режиме командной строки или загрузить другое приложение WIMP.

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

Нам представляется, что второй и третий подходы, дающие пользователю возможность выбора, являются предпочтительными.

Принцип согласованности интерфейса диктует необходимость для всех разработчиков приложений обеспечивать однотипный интерфейс в разных приложениях. Естественным решением является возможность для разработчиков приложений использовать те же модули и объекты, которые используются для построения WIMP-интерфейса ОС. В случае встроенного в ОС графического интерфейса системные объекты, обеспечивающие интерфейсные функции, делаются доступными для пользователей через соответствующий API (Windows). В случае интерфейса, представляющего собой интегрированное с ОС приложение, библиотека интерфейсных функций и объектов поставляется в составе ОС (Object Class Library в OS/2). Основой независимых графических интерфейсов являются независимые инструментальные средства, на основе которых может быть построен тот или иной WIMP-интерфейс.

Одной из наиболее успешных систем для построения таких интерфейсов является X Window, созданная в Массачусетском Технологическом Институте. Архитектура X Window построена по принципу клиент/сервер. Взаимодействие X-клиента и X-сервера происходит в рамках прикладного уровня - X-протокола. Для X Window безразличен транспортный уровень передачи, таким образом, X-клиент и X-сервер могут располагаться на разных компьютерах, в разных аппаратных и операционных средах, то есть, программа может осуществлять ввод-вывод графической информации на экран другого компьютера. Все различия в аппаратных и программных архитектурах X-клиента и X-сервера сглаживаются стандартом X-протокола. На базе инструментальных средств X Window было создано несколько сред WIMP-интерфейсов, наиболее популярный из которых, по-видимому, - Motif, являющийся стандартом Open Software Foundation.

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

Контрольные вопросы

  1. В каких случаях целесообразно задавать условия выполнения программы в виде параметров глобального окружения, в виде параметров локального окружения, в виде параметров вызова?
  2. Почему параметры вызова программы всегда имеют тип строки символов?
  3. Что такое конвейеризация и чем она обеспечивается? Приведите примеры задач, легко решаемых при помощи конвейеризации.
  4. Какие необязательные свойства командного интерпретатора могут сделать его более удобным в использовании?
  5. Как при параллельном выполнени нескольких процессов в режиме командной строки определить процесс, выдавший сообщение на экран? Как адресовать ответ оператора определенному процессу?
  6. Синтаксис язык C-shell создавался на основе языка программирования C, синтаксис языка REXX - на основе PL/1. В чем принципиальное отличие языков C-shell и REXX от их прототипов?
  7. Назовите основные элементы интерфейса WIMP и их функции.
  8. Какие свойства интерфейса WIMP полностью следуют метафоре рабочего стола? Какие ее расширяют?
  9. Приведите соображения "за" и "против" встраивания графического интерфейса непосредственно в ОС.
  10. На примере X Window объясните концепцию аппаратно-независимого интерфейса.

НазадОглавлениеВперед
Индекс