Event Loop

Inden for datalogi er en hændelsesløkke [1] [2] [3] , meddelelsesforsender , meddelelsesløkke , meddelelsespumpe eller runtime  en softwarekonstruktion, der venter på ankomst og distribuerer hændelser eller meddelelser til programmet . Det fungerer ved at lave en anmodning til en intern eller ekstern "begivenhedsudbyder" (som typisk blokerer anmodningen, indtil hændelsen indtræffer), og derefter kalder den relevante hændelseshandler ("afsender hændelsen"). Eventloopet kan bruges i forbindelse medet reaktordesignmønster, hvis hændelsesudbyderen er i overensstemmelse med en filgrænseflade , der kan vælges (hvilket betyder valgmetoden) eller "polles" (hvilket betyder et Unix-systemkald, ikke egentlig polling ). Hændelsesløkken kører næsten altid asynkront med afsenderen.

Når hændelsessløjfen danner det centrale flow af kontrol , der udgør programmet, som det ofte er tilfældet, kan en sådan løkke kaldes hovedsløjfen eller hovedbegivenhedsløkken . Navnet er passende, fordi en sådan hændelsesløkke er på det højeste niveau af kontrolflow i et program.

Besked passerer

Meddelelsespumper, som man siger, "pumper" beskeder i programmet fra beskedkøen (vedhæftet og normalt administreret af operativsystemet) til behandling. I snæver forstand er begivenhedsløkken en af ​​metoderne til at implementere kommunikation mellem processer . Faktisk findes beskedhåndtering i mange systemer, inklusive på kerneniveauet af Mach -operativsystemet . Hændelsesløkken er en specifik implementeringsteknik for systemer, der bruger meddelelsesoverførsel .

Brug

Traditionelt blev programmer skrevet i en synkron stil: al interaktion med programmet var enten at sende data gennem kommandolinjeargumenter eller brugerinput. Denne tilgang viste sig at være uanvendelig til at skrive programmer, der bruger en grafisk grænseflade. For sådanne programmer er det mere bekvemt at bruge den asynkrone stil, hvor en registreret handler (funktion) kaldes på visse hændelser. For at implementere denne tilgang bruges en hændelsesløkke. Normalt giver operativsystemet en funktion til at vælge den næste meddelelse (som get_next_message(), og blokerer udførelsestråden, indtil der vises mindst én meddelelse. Løkketeksten udføres således kun, når der er noget at behandle. Hvis en behandler er registreret til dette besked, kaldes den. Som en generel regel udføres langvarige operationer, såsom interaktion med netværket, på andre udførelsestråde for at holde GUI'en responsiv.

Hændelsesløkken i pseudokode :

hovedfunktion _ initialisere() mens besked != stop besked := get_next_message() process_message(besked) ende mens ende funktion


Den asynkrone tilgang har fundet anvendelse i netværksprogrammering. For eksempel kan en nginx -server , der kører asynkront og bruger ikke-blokerende I/O, håndtere et meget større antal forbindelser end sine synkrone modparter, som skaber én tråd eller proces pr. klient.

Implementeringer

Unix

I Unix fører " alt er en fil " -paradigmet naturligvis til en hændelsesløkke baseret på filrelaterede hændelser. Læsning fra og skrivning til filer, kommunikation mellem processer, kommunikationsnetværk og enhedsadministration opnås alle ved hjælp af fil-I/O, hvor filer identificeres af filbeskrivelser . Systemkalder selectog pollgiver dig mulighed for at overvåge status for mange filbeskrivelser, for eksempel for at finde ud af, hvornår data bliver læse/skrive, fejl og andre hændelser relateret til filer. Disse opkald blokerer programudførelse i et vist tidsrum, indtil den anmodede hændelse opstår på en af ​​de observerede filbeskrivelser. Disse funktioner bliver langsommere med et stort antal filbeskrivelser, så deres mere moderne modstykker bruges: epoll på Linux og kqueue på FreeBSD. Alle disse opkald skal bruge ikke-blokerende filbeskrivelser.

Signalbehandling

En af de få funktioner i Unix, der ikke er i overensstemmelse med filgrænsefladen, er asynkrone hændelser ( signaler ). Signaler modtaget i en signalbehandler er små, begrænsede stykker kode, der kører, mens resten af ​​opgaven er suspenderet. Hvis et signal modtages og behandles, og opgaven er blokeret i select(), select()vil den afsluttes før tid med EINTR . Hvis der modtages et signal, mens koden kører på CPU'en , vil opgaven blive suspenderet mellem instruktionerne, indtil signalbehandleren er færdig.

Så den oplagte måde at håndtere signaler på for signalhandlere er at indstille et globalt flag og inkludere en check for det flag i hændelsesløkken umiddelbart før og efter opkaldet select(), og hvis det er indstillet, skal du håndtere signalet på samme måde som hændelser med håndtag . Desværre fører dette til en løbstilstand : Hvis et signal ankommer umiddelbart mellem kontrol af flaget og opkald select(), vil det ikke blive behandlet, før det select()vender tilbage fra, eller af en anden grund (f.eks. afbrudt af en frustreret bruger).

Løsningen i POSIX er pselect , som ligner, select()men har en ekstra sigmask, der beskriver signalmasken . Dette gør det muligt for applikationen at maskere signaler i hovedopgaven og derefter fjerne masken, så længe kontrollen er i opkald select(), så signalbehandlere kun kaldes, mens applikationen er på en I/O-grænse . Implementeringer pselect()er dog først for nylig blevet pålidelige; versioner før Linux 2.6.16 har ikke syscallet pselect() , hvilket tvinger Glibc til at emulere det med en metode, der er tilbøjelig til den samme racetilstand som pselect().

En alternativ og mere bærbar løsning er at konvertere asynkrone hændelser til filbaserede hændelser ved hjælp af pipe-to-self tricket [4] , hvor "en signalhandler skriver en byte til en pipe , hvis anden ende observeres af et opkald pselect()i hovedprogram". [5] I Linux-kerneversionen 2.6.22 blev der tilføjet et nyt systemkald, signalfd()der gør det muligt at modtage signaler via en speciel filbeskrivelse.

Microsoft Windows

Ud over ikke-blokerende I/O, som bruger I/O-multiplekseringsfunktioner såsom WSAPol eller select , leverer Microsoft Windows også asynkron I/O. For asynkrone I/O-operationer er der Overlappet I/O . Hvis blokeringsfunktioner såsom ReadFile() eller WriteFile() sendes en struktur som et af argumenterne OVERLAPPED, vil disse funktioner øjeblikkeligt returnere kontrol til programmet. Du kan finde ud af færdiggørelsen af ​​operationen ved hjælp af tilbagekaldsfunktionen eller Input/output-afslutningsporten ( russisk I/O- afslutningsport ).

Ud over I/O har Windows en hændelsesløkke til grafiske applikationer. "Hjertet" i sådanne applikationer er WinMain() -funktionen , som kalder GetMessage() i en løkke. GetMessage() blokerer indtil en begivenhed ankommer (der er også et ikke-blokerende alternativ i form af PeekMessage() ). Dernæst, efter lidt behandling, kaldes DispatchMessage() , som sender hændelsesmeddelelsen til den relevante handler, også kendt som WindowProc . Meddelelser, for hvilke der ikke er registreret en handler, videregives til standardbehandleren ( DefWindowProc )

Se også

Noter

  1. Retabouil, Sylvain. Android NDK. Udvikling af applikationer til Android i C/C++. - M. : DMK Press, 2012. - S. 190. - 496 s. - ISBN 978-5-94074-657-7 .
  2. Budilov Vadim Anatolyevich. Internet programmering i Java. - Petersborg: BHV, 2003. - S. 41. - 704 s.
  3. Lamothe, André. Programmering af 3D-spil til Windows. 3D-grafik og rasterisering Pro-tip (+ cd-rom) = tricks fra 3D-spilprogrammeringsguruer: Avanceret 3D-grafik og rasterisering. - M. : Williams, 2006. - S. 73. - 1415 s. - ISBN 5-8459-0627-X , 0-672-31835-0.
  4. DJ Bernstein. Selvpibe-tricket .
  5. BUGS, pselect(2): Synchronous   I/O multiplexing - Linux - udviklermanpage - systemkald