Sind stop() cancel() oder quit() asynchron?

Komponenten, Dienste oder Micro-Services stellen gerne Funktionen wie start() run() oder execute() bereit, die einen spezifischen Arbeitsprozess initiieren. Nicht selten sind solche Routinen asynchron, sie veranlassen intern den Ausführungs-Start (z.B. in einem anderen Thread) und kehren unmittelbar mit einer Erfolgs- oder Fehlermeldung zurück.

Die Ausführungsumgebungen des Initiators und der Komponente sind getrennt.

Jetzt brauchen wir natürlich auch eine Möglichkeit um die Komponente zu informieren, dass sie ihre Tätigkeit einstellen bzw. abbrechen soll.

Und hier haben wir es meist mit einem stop() cancel() oder quit() zu tun. Die große Frage ist: Sind diese Routinen:

  1. asynchron: Also veranlassen sie nur das Beenden der Ausführung und kehren sofort zum Aufrufer zurück.
  2. synchron: Sie veranlassen das Beenden und warten so lange, bis die Ausführung tatsächlich gestoppt ist.

Beide Fälle sind allgemein betrachtet kompliziert und haben Seiteneffekte.

Im Fall 1 (asynchron) braucht man für ein sauberes Herunterfahren nun eine get_status() Funktion, die einem anzeigt, ob die Komponente nun schon ihre Aufgaben eingestellt hat oder noch arbeitet.
Das ist besonders wichtig beim Beenden eines Programms (bzw. für C++ Fans: im Destruktor). Schließlich dürfen wir keine Ressourcen freigeben, mit denen die Komponente vielleicht noch arbeitet.
Beim Herunterfahren muss also so lange gewartet werden, bis die Komponente wirklich fertig ist … man macht die asynchrone Funktion wieder synchron. (Schlimmer noch … wir pollen drauf.

Der zweite Fall (synchron) klingt simpler, denn hier kann die Komponente theoretisch ganz leicht “auf sich selbst” warten, und erst dann zurückkehren, wenn alles korrekt beendet ist.

… wäre da nicht der Fall des Beenden als Reaktion auf ein Event.
Der Klassiker: Die Komponente löst einen Callback aus, dieser wird im Komponenten-Besitzer ausgeführt, der das Löschen der Komponente veranlassen soll.
Hier wird versucht die Komponente freizugeben während sie noch aktiv arbeitet. Unsere stop(), cancel() oder quit() Funktionen würden endlos warten, weil die Komponente über die laufende Callback-Funktion am Leben gehalten wird.

Das erfordert also, dass unsere Komponente intern so aufgebaut ist, dass sie diesen Fall erkennt und die Beendigungsfunktion sofort zurückkehrt. Es dürfen keine geteilten Ressourcen mehr existieren und nach dem Rückkehren der Event-Funktion muss sich die Komponente schleunigst selbst freigeben.


In C++ haben wir hier ein verwandtes Thema:
Darf eine C++ Methode den Code delete this; ausführen?

Die kurze Antwort lautet: Ja, aber nur wenn es die letzte Anweisung ist, die this explizit oder implizit nutzt … und auch keine lokalen Objekte direkt oder indirekt bei ihrer Freigabe mit this interagieren, denn deren Destruktor läuft schließlich nach delete this.

Am Ende steht immer eines im Mittelpunkt: Nämlich dass der Programmierer ein ordentliches und korrektes State-Management etabliert hat.


Wenn sich eine triviale Erkenntnis mit Dummheit in der Interpretation paart, dann gibt es in der Regel Kollateralschäden in der Anwendung.
frei zitiert nach A. Van der Bellen
... also dann paaren wir mal eine komplexe Erkenntnis mit Klugheit in der Interpretation!