Добавил:
Upload Опубликованный материал нарушает ваши авторские права? Сообщите нам.
Вуз: Предмет: Файл:
ВС.docx
Скачиваний:
1
Добавлен:
01.03.2025
Размер:
9.58 Mб
Скачать

1.6.3. Программирование с управлением по сообщениям (событиям)

Программирование с управлением по сообщениям (событиям) - это технология программирования, вошедшая в употребление задолго до появления таких систем, как X Window. Она была положена в основу многих других систем с графическим оконным интерфейсом, в том числе и в основу такой широко распространенной для персональных ЭВМ среды, как Microsoft Windows. В настоящее время практически все многооконные системы базируются на этой технологии (сам термин "сообщение" - "message" - привнесен в эту технологию уже из среды MS Windows, в X Window более употребителен термин "событие" - "event").

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

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

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

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

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

Механизм, который позволяет прикладной программе не передавать управление ОС до наступления очередного события, называется механизмом "непринудительной многозадачности" (nonpreemptive multitasking). Термин "непринудительной" связан с тем, что прикладная программа сама проявляет инициативу и передает управление системе при выборке очередного сообщения, а до тех пор управление будет находиться под контролем этой программы и не может быть отнято у нее ОС "принудительно". Этим он отличается от истинного механизма многозадачности - "принудительной многозадачности" (preemptive multitasking) - который реализован в большинстве современных ОС и обеспечивает работу истинно параллельных процессов. В системе X Window механизм "непринудительной многозадачности" является мощным средством, поскольку сочетается с многозадачностью ОС UNIX или Linux. В среде Windows 95/98и более ранних версий он являлся основным средством параллельного выполнения программ.

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

  1. Создание программ для системы X Window. Библиотеки, используемые при разработке программ, для UNIX-подобных систем.

1.6.2. Создание программ для системы X Window

Для того чтобы программировать прикладные программы для системы X Window совсем не обязательно знать детали реализации сервера и протокола обмена данными. Система предоставляет библиотеку процедур, с помощью которых прикладные программы могут осуществлять доступ к услугам системы X Window.

Библиотека процедур называется "Xlib". Она входит в комплект поставки дистрибутива всех современных ОС типа UNIX или Linux (как правило, в ОС она располагается в библиотечном файле lX11.a или аналогичном ему в каталоге "/usr/lib"). Прототипы функций библиотеки, используемые ею структуры данных, типы и прочее определены в файлах, расположенных в каталоге "/usr/include/X11". Регистр букв здесь и далее везде имеет значение, а буква "X" в ОС типа UNIX - это наиболее употребительный знак, присущий всему, что связано с системой X Window.

Каждую программу для X Window можно условно разбить на три части: подготовительную часть, которая отвечает за установление связи с сервером и подготовку начальных данных; основную часть, которая содержит цикл обработки сообщений; и функции, отвечающие за реакцию программы на различные события в системе. Более сложные программы могут содержать дополнительные модули, такие, как функция реакции на таймер или на отсутствие действий пользователя в системе.

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

Далее на простом примере рассмотрим последовательность действий и связанную с ней последовательность вызовов функций библиотеки Xlib.

Любая программа, работающая в системе X Window, начинается с того, что устанавливает связь с X сервером. В библиотеке Xlib этой цели служит функция XOpenDisplay. Ее аргумент определяет сервер, с которым надо установить связь. Если аргумент не задан (имеет значение NULL), то адрес сервера определяется окружением ОС, в котором запущена прикладная программа (этой цели служит переменная окружения DISPLAY и обычно она задает локальный X сервер). Адрес сервера имеет вид "host:server.screen", где host - имя компьютера, на котором запущен X сервер (обычно это имя "localhost"), server - номер сервера (на одном компьютере может быть запущено одновременно несколько X серверов), а screen - номер экрана (один сервер может управлять несколькими экранами). Два последних параметра чаще всего имеют значение "0", поэтому адрес сервера по умолчанию, как правило, имеет вид "localhost:0.0". Номер экрана в адресе указывать необязательно, система может выбрать его сама.

После того, как связь с сервером установлена, программа должна определить номер экрана по умолчанию - для этого служит функция DefaultScreen. Затем нужно создать окно и показать его на дисплее. Для создания окна можно использовать одну из двух функций: XCreateWindow или XCreateSimpleWindow. Вторая из них проще в использовании, имеет меньше параметров, но и предоставляет разработчику меньше возможностей. После того, как окно создано, менеджеру окон надо дать рекомендации о том, как его отображать (функция SetWindowManagerHints), а серверу - установить, какие события будет обрабатывать прикладная программа (функция XSelectInput). Теперь окно можно выводить на экран. Чтобы отобразить окно на экране, используется функция XMapWindow. На этом подготовительная часть программы заканчивается.

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

Для получения у системы очередного события служит функция XNextEvent. Она помещает всю информацию о наступившем событии в структуру типа XEvent. Затем определяется тип наступившего события - для этого служит поле структуры XEvent.type. В общем виде цикл обработки событий (сообщений) на основе библиотеки Xlib в прикладной программе для X Window на языке "Си" имеет примерно следующий вид:

...

Display* ptDisplay;

XEvent ptEvent;

...

while (1)

{

XNextEvent(ptDisplay,&ptEvent);

switch (ptEvent.type)

{

case ...

...

case ...

...

} /* end switch */

}/* end while */

...

Программа в системе X Window завершается по выбранному разработчиком событию обычным образом (достаточно вызвать функцию exit). Для корректного завершения работы программы с X сервером (разрыва соединения) нужно вызвать функцию XСloseDisplay.