Из Википедии, бесплатной энциклопедии
Перейти к навигации Перейти к поиску

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

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

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

Передача сообщений [ править ]

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

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

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

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

Использование [ править ]

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

функция главная инициализировать () пока сообщение! = выйти сообщение: = get_next_message () process_message (сообщение) конец,  пока конечная  функция

Файловый интерфейс [ править ]

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

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

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 (),  если  x_fd  в  changed_fds :  process_x_messages()

Обработка сигналов [ править ]

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

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

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

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

Реализации [ править ]

Приложения Windows [ править ]

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

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

Порядок сообщений [ править ]

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

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

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, что позволяет любое сообщение (эквивалент вызова функции в не- отражательных времени работы) , которые будут поставлены в очередь для отправки к любому объекту.

См. Также [ править ]

  • Асинхронный ввод / вывод
  • Событийно-ориентированное программирование
  • Межпроцессного взаимодействия
  • Передача сообщений
  • Игровой цикл в программировании игр

Ссылки [ править ]

  1. ^ "Linux_2_6_16 - новички в ядре Linux" . kernelnewbies.org . Источник 2021-03-03 .
  2. ^ DJ Bernstein. "Уловка с трубкой" .
  3. ^ ОШИБКИ,:pselect(2)мультиплексирование синхронного ввода / вывода -  Руководство программиста Linux - Системные вызовы
  4. ^ Функция GetMessage () со списком приоритетов сообщений.

Внешние ссылки [ править ]

  • Блуждание по лабиринту маршрутизации сообщений и команд MFC
  • Использование сообщений и очередей сообщений (MSDN)
  • Использование оконных процедур (MSDN)
  • WindowProc (MSDN)