Цикл событий

редактировать

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

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

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

Содержание
  • 1 Передача сообщений
  • 2 Альтернативные конструкции
  • 3 Использование
  • 4 Файловый интерфейс
    • 4.1 Обработка сигналов
  • 5 Реализации
    • 5.1 Приложения Windows
      • 5.1.1 Порядок сообщений
    • 5.2 X Window System
      • 5.2.1 Цикл событий Xlib
    • 5.3 Цикл событий GLib
    • 5.4 Циклы выполнения macOS Core Foundation
  • 6 См. Также
  • 7 Ссылки
  • 8 Внешние links
Передача сообщений

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

Альтернативные схемы

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

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

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

function main initialize () while message! = Quit message: = get_next_message () process_message (message) endwhileend function
Файловый интерфейс

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

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

def main (): file_fd = open ("logfile.log") x_fd = open_display () construct_interface () while changed_fds == select ({file_fd, x_fd}) : if file_fd in changed_fds: data = read_from (file_fd) append_to_display (data) send_repaint_message () if x_fd in changed_fds: process_x_messages ()

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

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

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

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

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

Реализации

Приложения Windows

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

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

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

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

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

X Window System

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

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

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

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

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

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

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

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

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

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

См. Также
Ссылки
Внешние ссылки
Последняя правка сделана 2021-05-19 08:35:58
Содержание доступно по лицензии CC BY-SA 3.0 (если не указано иное).
Обратная связь: support@alphapedia.ru
Соглашение
О проекте