Ereignisschleife

Im Informatik, das Ereignisschleife ist ein Programmierkonstrukt oder Designmuster das wartet auf und sendet Veranstaltungen oder Mitteilungen in einem Programm. Die Ereignisschleife funktioniert, indem er eine Anfrage an einen internen oder externen "Ereignisanbieter" anfordert (das im Allgemeinen Blöcke Die Anfrage, bis ein Ereignis angekommen ist), und ruft dann die relevanten Event -Handler ("Versand das Ereignis"). Die Ereignisschleife wird manchmal auch als die bezeichnet Nachrichten Dispatcher, Nachrichtenschleife, Meldungspumpe, oder Schleife laufen.

Die Ereignisschleife kann in Verbindung mit a verwendet werden Reaktor, wenn der Ereignisanbieter dem folgt Dateischnittstelle, die ausgewählt oder "befragt" werden können (der Unix -Systemaufruf, nicht tatsächlich Umfragen). Die Ereignisschleife arbeitet fast immer asynchron mit dem Message Originator.

Wenn die Ereignisschleife das Zentral bildet Steuerfluss Konstrukt eines Programms, wie es oft der Fall ist, kann es als als als bezeichnet werden Hauptschleife oder Hauptereignisschleife. Dieser Titel ist angemessen, da eine solche Ereignisschleife auf höchstem Niveau innerhalb des Programms liegt.

Nachrichtenübergang

Nachrichtenpumpen sollen Nachrichten aus dem Programm "pumpen" Meldungswarteschlange (Zugewiesen und normalerweise im Besitz des zugrunde liegenden Betriebssystems) in das Programm zur Verarbeitung. Im strengsten Sinne ist eine Ereignisschleife eine der Methoden zur Implementierung Interprozesskommunikation. In der Tat gibt es in vielen Systemen, einschließlich a Kernel-Ebene Komponente der Mach -Betriebssystem. Die Ereignisschleife ist eine spezifische Implementierungstechnik von Systemen, die verwendet werden Nachrichtenübergang.

Alternative Designs

Dieser Ansatz steht im Gegensatz zu einer Reihe anderer Alternativen:

  • Traditionell lief ein Programm einfach einmal und beendete dann. Diese Art von Programm war in den frühen Tagen des Computertagens sehr häufig und fehlte irgendeiner Form der Benutzerinteraktivität. Dies wird immer noch häufig verwendet, insbesondere in Form von Befehlszeilenbetrieben Programme. Irgendein Parameter werden im Voraus eingerichtet und auf einmal vergangen, wenn das Programm beginnt.
  • Menügesteuerte Designs. Diese können immer noch eine Hauptschleife enthalten, werden aber normalerweise nicht als als angesehen ereignisgesteuert im üblichen Sinne. Stattdessen erhält der Benutzer eine immer schwere Reihe von Optionen, bis die Aufgabe, die er ausführen möchte, die einzige verfügbare Option ist. Eine begrenzte Interaktivität durch die Menüs ist verfügbar.

Verwendungszweck

Aufgrund der Vorherrschaft von Grafische BenutzeroberflächenDie meisten modernen Anwendungen verfügen über eine Hauptschleife. Das get_next_message () Routine wird normalerweise vom Betriebssystem bereitgestellt, und Blöcke bis eine Nachricht verfügbar ist. Somit wird die Schleife nur eingegeben, wenn etwas zu verarbeiten ist.

Funktion Haupt initialize () während Nachricht! = Meldung beenden: = get_next_message () process_message (Nachricht) Ende während Ende Funktion 

Dateischnittstelle

Unter Unix, das "Alles ist eine Datei"Paradigm führt natürlich zu einer dateibasierten Ereignisschleife. Lesen und Schreiben von Dateien, Inter-Process-Kommunikation, Netzwerkkommunikation und Gerätesteuer Dateideskriptor. Das auswählen und Umfrage Mit Systemaufrufen können eine Reihe von Dateideskriptoren für eine Zustandsänderung überwacht werden, z. Wenn Daten verfügbar sind.

Betrachten Sie beispielsweise ein Programm, das aus einer kontinuierlich aktualisierten Datei liest und deren Inhalt in der angezeigt wird X Fenstersystem, was mit Kunden über eine Steckdose kommuniziert (entweder Unix -Domäne oder Berkeley):

def hauptsächlich():  Datei_fd = offen("logfile.log")  x_fd = open_display()  construct_interface()  während WAHR:  Riste, _, _ = auswählen.auswählen[Datei_fd, x_fd], [],, []):  wenn Datei_fd in Riste:  Daten = Datei_fd.lesen()  append_to_display(Daten)  send_repaint_message()  wenn x_fd in Riste:  process_x_messages() 

Handhabungssignale

Eines der wenigen Dinge in Unix, die nicht der Dateischnittstelle entsprechen, sind asynchrone Ereignisse (Signale). Signale werden in empfangen Signalhandler, kleine, begrenzte Codestücke, die ausgeführt werden, während der Rest der Aufgabe suspendiert wird; Wenn ein Signal empfangen und behandelt wird, während die Aufgabe einblockiert auswählen(), Select wird früh mit dem zurückkehren mit Eintr; Wenn ein Signal empfangen wird, während die Aufgabe ist CPU gebundenDie Aufgabe wird zwischen Anweisungen aufgehängt, bis der Signalhandler zurückkommt.

Eine offensichtliche Möglichkeit, Signale zu verarbeiten auswählen() Anruf; Wenn es festgelegt ist, verarbeiten Sie das Signal auf die gleiche Weise wie bei Ereignissen in Dateideskriptoren. Leider führt dies zu einem Rassenbedingung: Wenn ein Signal sofort zwischen der Überprüfung der Flagge und dem Anruf ankommt auswählen(), es wird erst behandelt, bis auswählen() Rückgabe aus einem anderen Grund (zum Beispiel von einem frustrierten Benutzer unterbrochen).

Die Lösung kam zu Posix ist der pSelect () Anruf, der ähnlich ist wie auswählen() dauert aber zusätzliche Sigmask Parameter, der a beschreibt Signalmaske. Dadurch kann eine Anwendung Signale in der Hauptaufgabe maskieren und die Maske für die Dauer der Dauer entfernen auswählen() Rufen Sie so auf, dass Signalhandler nur aufgerufen werden, während die Anwendung ist E/O gebunden. Implementierungen von jedoch pSelect () waren nicht immer zuverlässig; Versionen von Linux vor 2.6.16 haben keine pSelect () Systemanruf,[1] zwingen Glibc Um es über eine Methode zu emulieren, die zu demselben Rassenbedingung neigen pSelect () soll vermeiden.

Eine alternative, tragbarere Lösung besteht darin, asynchrone Ereignisse in Datei-basierte Ereignisse mithilfe des Selbstpfropftrick,[2] wo "ein Signalhandler ein Byte in ein Rohr schreibt, dessen anderes Ende von überwacht wird auswählen() im Hauptprogramm ".[3] Im Linux Kernel Version 2.6.22, ein neuer Systemanruf Signalfd () wurde hinzugefügt, wodurch das Empfangen von Signalen über einen Sonderdateideskriptor empfangen wird.

Implementierungen

Windows -Anwendungen

Auf der Microsoft Windows Betriebssystem, ein Prozess, der mit dem Benutzer interagiert muss Akzeptieren und reagieren Sie auf eingehende Nachrichten, die von a fast unvermeidlich gemacht werden Nachrichtenschleife in diesem Prozess. In Windows wird eine Nachricht einem Ereignis gleichgesetzt, das dem Betriebssystem erstellt und auferlegt wurde. Ein Ereignis kann unter anderem Benutzerinteraktion, Netzwerkverkehr, Systemverarbeitung, Timeraktivität, Inter-Process-Kommunikation sein. Für nicht interaktive, nur E/A-Ereignisse hat Windows E/A -Abschlussports. E/A -Abschlussanschluss -Schleifen laufen getrennt von der Nachrichtenschleife aus und interagieren Sie nicht mit der Nachrichtenschleife außerhalb der Box.

Das "Herz" der meisten Win32 Anwendungen ist der Winmain () Funktion, die aufruft GetMessage () in einer Schleife. GetMessage () Blöcke, bis eine Nachricht oder "Ereignis" empfangen wird (mit Funktion Peekmessage () als nicht blockierende Alternative). Nach einer optionalen Verarbeitung wird es angerufen SendatchMessage (), der die Nachricht an den entsprechenden Handler sendet, auch bekannt als Fensterproc. Normalerweise haben Nachrichten, die kein Besonderes haben WindowProc () werden entsandt zu DefwindowProc, der Standard. SspatchMessage () ruft den Fensterproc von der auf Hwnd handhaben der Nachricht (registriert mit dem RegisterClass () Funktion).

Nachrichtenbestellung

Neuere Versionen von Microsoft Windows garantieren dem Programmierer, dass Nachrichten an die Nachrichtenschleife einer Anwendung in der Reihenfolge übermittelt werden, dass sie vom System und seiner Peripheriegeräte wahrgenommen wurden. Diese Garantie ist unerlässlich, wenn die Konstruktionsfolge von entworfen wird Multithread Anwendungen.

Einige Nachrichten haben jedoch unterschiedliche Regeln, z. B. Nachrichten, die immer zuletzt empfangen werden, oder Nachrichten mit einer anderen dokumentierten Priorität.[4]

X Fenstersystem

XLIB -Ereignisschleife

X Anwendungen verwenden Xlib direkt um die gebaut werden XNexeVent Funktionsfamilie; XNexeVent Blöcke, bis ein Ereignis in der Ereigniswarteschlange erscheint, woraufhin die Bewerbungsprozesse angemessen verarbeitet. Die XLIB -Ereignisschleife verarbeitet nur Fenstersystemereignisse. Anwendungen, die in der Lage sein müssen, auf anderen Dateien und Geräten warten zu können ConnectionNumber, aber in der Praxis neigen dazu zu verwenden Multithreading.

Sehr wenige Programme verwenden XLIB direkt. Im häufigeren Fall unterstützen GUI -Toolkits, die auf XLIB basieren, normalerweise das Hinzufügen von Ereignissen. Zum Beispiel Toolkits basierend auf XT Intrinsics haben XTAppadDinput () und XTAppaddTimeout ().

Bitte beachten Sie, dass es nicht sicher ist, XLIB -Funktionen von einem Signalhandler aufzurufen, da die X -Anwendung möglicherweise in einem willkürlichen Zustand unterbrochen wurde, z. innerhalb XNexeVent. Sehen [1] Für eine Lösung für X11R5, X11R6 und XT.

Glib Event Loop

Das Glib Die Ereignisschleife wurde ursprünglich für die Verwendung in der Verwendung erstellt Gtk wird aber jetzt auch in Nicht-GUI-Anwendungen verwendet, wie z. D-Bus. Die befragte Ressource ist die Sammlung von Dateideskriptoren Die Bewerbung ist interessiert; Der Wahlblock wird unterbrochen, wenn a Signal kommt an oder a Auszeit läuft ab (z. B. wenn die Anwendung eine Zeitlimit- oder Leerlaufaufgabe angegeben hat). Während GLIB integrierte Unterstützung für Ereignisse für Dateideskriptor und untergeordnete Beendigung hat, ist es möglich, eine Ereignisquelle für jedes Ereignis hinzuzufügen, das in einem Vorbereitungs-Check-Dispatch-Modell behandelt werden kann.[2]

Anwendungsbibliotheken, die auf der GLIB -Ereignisschleife basieren Gstreamer und die asynchroner i/o Methoden von Gnomevfs, aber Gtk bleibt die sichtbarste Kundenbibliothek. Ereignisse aus dem Fenstersystem (in X, lesen Sie das x ab Steckdose) werden übersetzt von GDK in GTK -Ereignisse und emittiert als Glib -Signale auf den Widget -Objekten der Anwendung.

MacOS Core Foundation Run Loops

Genau ein Cfrunloop ist pro Thread zulässig, und es können willkürlich viele Quellen und Beobachter angebracht werden. Quellen kommunizieren dann mit Beobachtern über die Laufschleife, wobei die Warteschlange und den Versand von Nachrichten organisiert werden.

Die Cfrunloop ist abstrahiert in Kakao Als nsrunloop, das jede Nachricht ermöglicht (gleichwertig einem Funktionsaufruf in Nichtsreflektierend Laufzeiten) für den Versand in ein Objekt in der Warteschlange gestellt werden.

Siehe auch

Verweise

  1. ^ "Linux_2_6_16 - Linux -Kernel -Neulinge". kernelnewbies.org. Abgerufen 2021-03-03.
  2. ^ D. J. Bernstein. "Der Selbstpfropftrick".
  3. ^ Käfer, Pelect (2): Synchrones E/A -Multiplexing -Linux Programmierer Handbuch - Systemaufrufe
  4. ^ GetMessage () Funktion mit Meldungsprioritätsliste.

Externe Links