Funktion IPS_SemaphoreGet

Ich hatte den Wunsch nach einer neuen „Funktion IPS_SemaphoreGet“ für alle IPS-Versionen bewußt hier in diesem Bereich über Funktionswünsche ‚Ideen und Vorschläge für IP-Symcon‘ gepostet; ein Moderatoren-Roboter muß sie wohl gescannt haben und hat sie beim Stichwort „L****“ gleich in den m.E. falschen Test Bereich (Ubuntu, RaspberryPi, Mac OSX) verschoben :confused:. Deshalb hier nochmal mein Wunsch ohne den Teil mit dem anstößigen Stichwort:

Für die Ablaufsteuerung gibt es die beiden IPS-Funktionen zum Setzen und Löschen von Semaphoren

IPS_SemaphoreEnter
IPS_SemaphoreLeave

Diese Befehle Setzen bzw. Löschen ein Semaphor (ein Zeichen mit Signalwirkung), „das dazu verwendet werden kann, den Start anderer Skripte zu verhindern“.

Ich verwende Semaphoren auch um den gleichzeitigen Zugriff auf Variablen zu verhindern und um Nachzuprüfen, ob ein bestimmtes Skript noch ausgeführt wird (wenn ein Skript abbricht oder abgebrochen wird, löscht IPS ja glücklicherweise alle von dem Skript gesetzten Semaphoren).
Dazu wäre eine Funktion nützlich, die ein Semaphor abprüft ohne es selbst zu setzen, also mit folgenden Leistungsmerkmalen:

IPS_SemaphoreGet

boolean IPS_SemaphoreGet ( string $Name )

Parameterliste
Name Name, der die Semaphore beschreibt.

Rückgabewerte
TRUE, wenn die Semaphore bereits gesetzt ist. FALSE, wenn die Semaphore noch nicht gesetzt ist. Die Funktion verändert den Wert der Semaphore nicht.

Ich wünsche mir diese Funktion für alle Versionen von IPS.

Viele Grüsse
Harald

Warum nutzt du nicht IPS_SemaphoreEnter mit einem Timeout von 1ms?


function IPS_SemaphoreIsLocked($Name) {
  if(IPS_SemaphoreEnter($Name, 1)) {
    IPS_SemaphoreLeave($Name);
    return false;
  } else {
    return true;
  }
}

Trotzdem ist es gefährlich auf die Rückgabe von der Funktion zu vertrauen, da ein anderer Thread dir deinen „angeblich“ freien Slot jederzeit klauen kann. Im Sinne der Sychronisierung hat deine Funktion nämlich wenig Vorteile.

paresy

Auf ähnliche Probleme bin ich auch gestoßen.

Dazu habe ich mir dann folgendes ausgedacht, vielleicht hilt es dir.

Eine unsortierte Warteschlange, welche nicht bei Eintritt von Semaphore wartet, sondern per IPS_Sleep, damit nicht, wenn die Semaphore zurückgegeben wird, sich zeitgleich 10 andere Threads sich draufstürzen.
Ich habe bei mir so lange ausprobiert bis ich auf ca. 2000 Versuche bei einer Wartezeit von 1-5 ms pro Versuch gelandet bin.
Da die Aktionen relativ schnell ausgeführt werden paßt das bei mir.


<?
for ($i = 0; $i < 2000; $i++)
{
    if (IPS_SemaphoreEnter((string) 58849, 1))
    {
        // Action ausführen
        $status = $client->{$action}();
        IPS_SemaphoreLeave((string) 58849);
        break;
    }
    else
    {
        IPS_Sleep(mt_rand(1, 5));
    }
}
if ($i == 2000)
{
    echo "Konnte Semaphore nicht setzen." . PHP_EOL;
    return false;
}
return $status;
?>

Um zu prüfen ob ein Script schon läuft, frage ich die Script-Threads ab.


<?
foreach (IPS_GetScriptThreadList() as $id)
{
    $thread = IPS_GetScriptThread($id);
    if (($thread['ScriptID'] == $_IPS['SELF']) && ($id <> $_IPS['THREAD']))
    {
        if ($_IPS['SENDER'] == "WebFront")
            WFC_SendNotification($_IPS['CONFIGURATOR'], "Bitte warten!", "Aktion gerade nicht möglich.", '', 5);
        else
            IPS_LogMessage("FritzBox", "Mehrfache Scriptausführung gefunden. Abbruch von Script (" . $_IPS['SELF'] . ") - " . IPS_GetName($_IPS['SELF']));
        return false;
    }
}?>

So habe ich es zu 99% geschafft alle Probleme mit meinen Scripten welche die FritzBox per SOAP Abfragen zu lösen.
Vorher haben sich die Scripte teilweise gegenzeitig bei den Abfragen blockiert oder die Box in die Knie gezwungen :smiley:
Michael

Das mache ich ja als Krücke, allerdings mit Wartezeit = 0 (in der Annahme, dass dann nur 1x aufgeprüft wird).

Ich halte es nur für eine „unelegante“ Programmierung, wenn ich mich auf einen Stuhl setzen muß um zu erkennen, dass der bereits besetzt ist :rolleyes:

Trotzdem ist es gefährlich auf die Rückgabe von der Funktion zu vertrauen, da ein anderer Thread dir deinen „angeblich“ freien Slot jederzeit klauen kann.

Das ist mir klar, vor dem Zugriff auf eine gesperrte Variable mache ich es schon so ähnlich wie von Dir vorgeschlagen mit nachlassender Prüf-Frequenz:

function SetIPSsem($Sem) {
    $i = 10;
    do {
        $i++;   // nothing
        if ( $i > 100 )
            die(IPS_GetScriptFile ($_IPS['SELF']) . ': Time-Out von Semaphore ' . $Sem . " (" . IPS_GetLocation($Sem) . ")");
    } while (IPS_SemaphoreEnter($Sem, $i) != true);
}

„IPS_SemaphoreGet“ würde ich auch nur verwenden, wenn die Sperre nicht aktuell gesetzt werden muß, z.B. für eine Liste der per Semaphoren gesperrten Skripte. Nicht zeitkritische Skript beginnen bei mir mit dem Statement

IPS_SemaphoreEnter($_IPS[‚SELF‘] , 0);

und können somit per Semaphore „verfolgt“ werden.

Das Thema liegt bei mir schon lange in der Pipeline und kam wieder hoch, als ich mich wieder mit der L******-Version beschäftigte (bei der diese Funktionen immer noch nicht implementiert sind), siehe mein verschobener Beitrag, der jetzt auch noch verschwunden ist. :confused:

Viele Grüsse
Harald

Danke für den Tip, sowas ähnliches mache ich ja schon, siehe mein vorheriges Posting.

Allerdings ohne die Funktion „IPS_GetScriptThreadList“, die scheint undokumentiert zu sein; die Online-Hilfe zeigt hierzu nur Beiträge im Forum, keine Funktions-Beschreibung.

Viele Grüsse
Harald