Цикл событий - Event loop

В Информатика, то цикл событий это программная конструкция или шаблон дизайна что ждет и отправляет События или Сообщения в программа. Цикл событий работает путем отправки запроса к какому-либо внутреннему или внешнему «поставщику событий» (который обычно блоки запрос до наступления события), затем вызывает соответствующий обработчик события («отправляет событие»). Цикл событий также иногда называют диспетчер сообщений, цикл сообщений, насос сообщений, или цикл выполнения.

Цикл событий может использоваться вместе с реактор, если провайдер событий следует файловый интерфейс, который может быть выбран или опрошен (системный вызов Unix, а не опрос ). Цикл событий почти всегда работает асинхронно с отправителем сообщения.

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

Передача сообщений

Говорят, что насосы сообщений «перекачивают» сообщения из программных очередь сообщений (назначенный и обычно принадлежащий базовой операционной системе) в программу для обработки. В самом строгом смысле цикл событий - это один из методов реализации межпроцессного взаимодействия. Фактически, обработка сообщений существует во многих системах, включая уровень ядра компонент Операционная система Mach. Цикл событий - это особый метод реализации систем, использующих передача сообщений.

Альтернативные конструкции

Этот подход отличается от ряда других альтернатив:

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

Применение

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

функция основная инициализация () в то время как message! = выйти из сообщения: = get_next_message () process_message (сообщение) конец в то время какконец функция

Файловый интерфейс

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

Например, рассмотрим программу, которая читает из постоянно обновляемого файла и отображает его содержимое в X Window System, который общается с клиентами через сокет (либо Домен Unix или Беркли ):

def основной():    file_fd = открыто("logfile.log")    x_fd = open_display()    construct_interface()    в то время как changed_fds == Выбрать({file_fd, x_fd}):        если file_fd в changed_fds:            данные = read_from(file_fd)            append_to_display(данные)            send_repaint_message()        если x_fd в changed_fds:            process_x_messages()

Обработка сигналов

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

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

Решение пришло POSIX это pselect () вызов, который похож на Выбрать() но требует дополнительных сигмаска параметр, описывающий сигнальная маска. Это позволяет приложению маскировать сигналы в основной задаче, а затем удалять маску на время Выбрать() вызов так, что обработчики сигналов вызываются только пока приложение Ограничение ввода / вывода. Однако реализации pselect () только недавно[когда? ] стать надежным; версии Linux до 2.6.16 не имеют pselect () системный вызов, форсирование glibc эмулировать его с помощью метода, подверженного тому же самому состоянию гонки pselect () предназначен для того, чтобы избежать.

Альтернативным, более переносимым решением является преобразование асинхронных событий в события на основе файлов с помощью трюк с трубкой,[1] где "обработчик сигнала записывает байт в канал, другой конец которого контролируется Выбрать() в основной программе ».[2] В Ядро Linux версия 2.6.22, новый системный вызов signalfd () добавлено, что позволяет получать сигналы через специальный файловый дескриптор.

Реализации

Приложения Windows

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

"Сердце" большинства Win32 Приложения это WinMain () функция, которая вызывает GetMessage () в петле. GetMessage () блокируется до тех пор, пока не будет получено сообщение или «событие» (с функцией PeekMessage () как неблокирующая альтернатива). После некоторой дополнительной обработки он вызовет DispatchMessage (), который отправляет сообщение соответствующему обработчику, также известному как WindowProc. Обычно сообщения, не имеющие особого WindowProc () отправляются в DefWindowProc, по умолчанию. DispatchMessage () вызывает WindowProc объекта HWND ручка сообщения (зарегистрированного с RegisterClass () функция).

Порядок сообщений

Более поздние версии Microsoft Windows гарантируют программисту, что сообщения будут доставлены в цикл сообщений приложения в том порядке, в котором они были восприняты системой и ее периферийными устройствами. Эта гарантия важна при рассмотрении проектных последствий многопоточный Приложения.

Однако некоторые сообщения имеют разные правила, например сообщения, которые всегда принимаются последними, или сообщения с другим задокументированным приоритетом.[3]

X Window System

Цикл событий Xlib

Икс приложения, использующие Xlib непосредственно построены вокруг XNextEvent семейство функций; XNextEvent блокируется до тех пор, пока событие не появится в очереди событий, после чего приложение обработает его соответствующим образом. Цикл событий Xlib обрабатывает только события оконной системы; приложения, которым необходимо иметь возможность ожидать других файлов и устройств, могут создавать свой собственный цикл обработки событий из таких примитивов, как ConnectionNumber, но на практике обычно используют многопоточность.

Очень немногие программы используют Xlib напрямую. В более общем случае наборы инструментов GUI, основанные на Xlib, обычно поддерживают добавление событий. Например, инструментарий на основе Xt Intrinsics имеют XtAppAddInput () и XtAppAddTimeout ().

Обратите внимание, что вызывать функции Xlib из обработчика сигналов небезопасно, поскольку приложение X могло быть прервано в произвольном состоянии, например в пределах XNextEvent. Увидеть [1] для решения для X11R5, X11R6 и Xt.

Цикл событий GLib

В GLib цикл событий изначально создавался для использования в GTK + но теперь используется и в приложениях без графического интерфейса, таких как D-автобус. Опрашиваемый ресурс - это набор файловые дескрипторы приложение заинтересовано; опрос будет прерван, если сигнал прибывает или тайм-аут истекает (например, если приложение указало тайм-аут или простаивающую задачу). В то время как GLib имеет встроенную поддержку дескрипторов файла и дочерних событий завершения, можно добавить источник событий для любого события, которое может быть обработано в модели подготовки-проверки-отправки.[2]

Библиотеки приложений, построенные на цикле событий GLib, включают GStreamer и асинхронный ввод / вывод методы GnomeVFS, но GTK + остается самой заметной клиентской библиотекой. События из оконная системаИкс, прочтите X разъем ) переведены GDK в события GTK + и испускаются как сигналы GLib на объектах виджетов приложения.

Циклы выполнения macOS Core Foundation

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

CFRunLoop абстрагируется в Какао как NSRunLoop, который позволяет любое сообщение (эквивалентно вызову функции в не-отражающий время выполнения) для постановки в очередь для отправки на любой объект.

Смотрите также

использованная литература

  1. ^ Д. Дж. Бернштейн. "Уловка с трубкой".
  2. ^ ОШИБКИ, pselect (2): мультиплексирование синхронного ввода / вывода -Linux Программиста Руководство по эксплуатации - Системные вызовы
  3. ^ Функция GetMessage () со списком приоритетов сообщений.

внешние ссылки