BlockingCall(): BlockingFn() Variable an AbortFn() übergeben

Begonnen von raspberry, 12 Januar 2021, 08:14:49

Vorheriges Thema - Nächstes Thema

raspberry

Guten Tag zusammen,

ich arbeite gerade an der Weiterentwicklung eines FHEM Moduls. Dafür führe ich einen BlockingCall aus, in dem eine Variable im $hash gespeichert wird. Diese Variable benötige ich dann in der AbortFn() des entsprechenden BlockingCalls. Jedoch ist die Variable in der AbortFn() nicht vorhanden. In der eigentlichen BlockingFn() wurde sie aber erfolgreich geschrieben, das habe ich überprüft.
Beim Aufruf des BlockingCalls wird ein $hash ($abortArg) für die AbortFn() übergeben. Wird dabei der aktuellste $hash, also nach Ausführung der BlockingFn() an die AbortFn() übergeben, oder handelt es sich um den $hash, der beim Aufruf des BlockingCalls vorhanden ist? Wenn dies der Fall ist, wie könnte ich eine entsprechende Variable von der BlockingFn() an die AbortFn() mit FHEM Mitteln übergeben?

Vielen Dank schon einmal für die Hilfe und viele Grüße

raspberry

KölnSolar

Das kennst Du ? Demnach ist es falsch den $hash im BlockingCall zu bearbeiten.
Das
Zitathandelt es sich um den $hash, der beim Aufruf des BlockingCalls vorhanden ist
ist, denke ich, die richtige Interpretation.
Grüße Markus
RPi3/2 buster/stretch-SamsungAV_E/N-RFXTRX-IT-RSL-NC5462-Oregon-CUL433-GT-TMBBQ-01e-CUL868-FS20-EMGZ-1W(GPIO)-DS18B20-CO2-USBRS232-USBRS422-Betty_Boop-EchoDot-OBIS(Easymeter-Q3/EMH-KW8)-PCA301(S'duino)-Deebot(mqtt2)-zigbee2mqtt

SCMP77

#2
Das ist nicht ganz trvial.

Der BlockingCall arbeitet immer in einer "Kopie". Dadurch kann man an den aufrufenden Prozess so ohne weiteres keinen Werte zurück geben.

Steht auch in der Wiki zum BlockingCall:

ZitatVeränderungen an internen Variablen von FHEM (Device Hashes, Timers, usw.) werden innerhalb eines BlockingCalls durchgeführt und sind dort auch sichtbar, haben aber keinerlei Einfluss auf den eigentlichen FHEM Hauptprozess und alle Definitionen. Solche Veränderungen müssen an die finishFn delegiert werden (z.B. durch zusätzliche Rückgabewerte), da es sich um einen Fork-Prozess handelt, der sich nach Abschluss des BlockingCall selbst zerstört.


Es gibt aber Methoden, mit denen man das erreichen kann, das eine wäre die Nutzung von Shared-Memory

https://okojj.github.io/ebook/books/perl2/cookbook/ch16_13.htm

Die Frage ist jedoch, ob das wirklich in Deinem Fall sinnvoll ist.

Wenn es um Timouts von Devices o.ä. geht, kann man diesen Timeout schon im BlockingCall-Prozess abfangen und dann den Prozess ganz normal beenden und einen entsprechenden Fehlerstatus als return-Wert zurück geben. Die finishFn könnte das dann auswerten und entsprechend darauf reagieren.
Raspberry Pi 3 Model B mit Rasbian, SolvisMax, AVM DECT 200, Sonoff mit Tasmota geflasht

rudolfkoenig

Anders formuliert:
- der BlockingCall Aufruf passiert in Prozess1 ("Haupt"-FHEM)
- die blockierende Funktion wird in Prozess2 ausgefuehrt. Hier sind alle anderen Verbindungen (bis auf die Telnet-"Nabelschnur" zum Haupt-FHEM) abgeklemmt. Aenderungen an Variablen haben nur hier (Prozess2) ihre Gueltigkeit, Prozess1 kriegt nichts mit.
- der Rueckgabewert der blockierenden Funktion in Prozess2 wird via telnet-Verbindung an das FinishFn uebergeben, FinishFn laeuft im Prozess1 (Haupt-FHEM)
- AbortFn wird in Prozess1 aufgerufen, wenn innerhalb der spezifizierten Zeit die blockierende Funktion nicht fertig ist. Davor wird Prozess2 terminiert (kill).
- fuer die Kommunikation von Prozess2 an Prozess1 steht neben Rueckgabewert/FinishFn Aufruf auch BlockingInformParent zur Verfuegung, sie verwendet auch die telnet Funktion.

BlockingCall ist meiner Ansicht nach nur berechtigt fuer CPU intensive Aufgaben, alles andere sollte in die Select-Schleife gehaengt werden. Das ist nicht immer trivial, weil viele Bibliotheken blockierend sind, aber effizienter und fuer den Endanwender mit weniger Seiteneffekte/Probleme verbunden.

raspberry

Ganz herzlichen Dank für die vielen, schnellen und ausführlichen Antworten! Ich bin echt begeistert! :D

ZitatDer BlockingCall arbeitet immer in einer "Kopie". Dadurch kann man an den aufrufenden Prozess so ohne weiteres keinen Werte zurück geben.

Das habe ich leider nicht gelesen.

Konkret zum Problem bzw. der Anforderung: Ich habe ein Gerät, bei dem man den Zustand (An/Aus) per UPnP Subscription erhalten kann. Ich habe nun den Server im BlockingCall laufen und erhalte darüber die Rückmeldung vom Gerät, das heißt der Server läuft die ganze Zeit, von FHEM läuft. Das Reading (die Rückmeldungen vom Gerät) schreibe ich vom BlockingCall bereits mit BlockingInformParent. Nachdem der Server beendet wurde, muss ich mich noch von der UPnP Subscription abmelden, das könnte ich dann auch über BlockingInformParent in der AbortFn machen.
Gäbe es eine andere Möglichkeit/Funktion den Server zu starten?

Vielen vielen Dank und beste Grüße!

rudolfkoenig

Zitatdas könnte ich dann auch über BlockingInformParent in der AbortFn machen.
AbortFn wird im Prozess1 (Haupt-FHEM) aufgerufen, wenn der Timer abgelaufen ist, und der BlockingCall Prozess (Prozess2) abgeschossen wird.
Hier BlockingInformParent aufzurufen ist vielleicht moeglich, aber definitiv ueberfluessig.

ZitatGäbe es eine andere Möglichkeit/Funktion den Server zu starten?
Ich verstehe die Frage nicht.

raspberry

Zitat von: rudolfkoenig am 12 Januar 2021, 15:03:12
AbortFn wird im Prozess1 (Haupt-FHEM) aufgerufen, wenn der Timer abgelaufen ist, und der BlockingCall Prozess (Prozess2) abgeschossen wird.
Hier BlockingInformParent aufzurufen ist vielleicht moeglich, aber definitiv ueberfluessig.
BlockingInformParent soll in der BlockingFn aufgerufen werden, um später die Variable in der AbortFn zur Verfügung zu haben.

Zitat von: rudolfkoenig am 12 Januar 2021, 15:03:12
Ich verstehe die Frage nicht.
Ich habe den Server für die UPnP Subscription in meinem aktuellen Ansatz über einen BlockingCall gestartet. Gibt es in FHEM dafür eine andere bzw. bessere Lösung?

herrmannj

ja, gibt es -> Die select loop. Schau mal in die source, fhem.pl und Implementierungen bspw Telnet etc.

vg
joerg

KölnSolar

Zitatfür die UPnP Subscription
Hab ich in "meiner" Version des DLNARenderer für das "renewal" der subscription auch, weil das in einem "Standard-Perl"-Modul blockierend stattfindet.
Aktuell bastele ich ja auf Basis des DLNARenderer an einem Universal-UPNP-Controller für FHEM. Bisher kann er bereits das discovery u. notify verarbeiten. Im nächsten Schritt kommt der subscription-Prozess hinzu. Vermutlich werde ich auch dort blockingCall einsetzen, weil die Perl-Lib blockierend arbeitet u. es leider keine vernünftige UPNP-Lib in Perl gibt.
Zitatja, gibt es -> Die select loop. Schau mal in die source, fhem.pl und Implementierungen bspw Telnet etc.
Wenn er auch diese vermaledeite Lib einsetzt, wird es vermutlich nicht gehen. :-\

Grüße Markus
RPi3/2 buster/stretch-SamsungAV_E/N-RFXTRX-IT-RSL-NC5462-Oregon-CUL433-GT-TMBBQ-01e-CUL868-FS20-EMGZ-1W(GPIO)-DS18B20-CO2-USBRS232-USBRS422-Betty_Boop-EchoDot-OBIS(Easymeter-Q3/EMH-KW8)-PCA301(S'duino)-Deebot(mqtt2)-zigbee2mqtt