Verständnisproblem bei Semaphore

Hallo liebe Liste :loveips:,

ich habe da mal ein Verständnisproblem zu Sempahore. Zum Hintergrund: Ich habe ein Script, das ich sehr häufig (etwa alle 5s) aufrufe, um den Zustand meines Receivers abzufragen (pollen nennt man das wohl). Um das Füllen der Warteschleife zu vermeiden, habe ich so wie in der Anleitung beschrieben die Semaphoremethode eingesetzt.

Am Anfang also:

if(!IPS_SemaphoreEnter("SR7007", 1 /* sehr kurz warten */)) {
 return; Läuft bereits

und dann am Ende:

IPS_SemaphoreLeave("SR7007");

Im Prinzip geht das, jedoch blockiert die ganze Geschichte nach einigen Stunden in der Form, dass das Script zwar startet, aber bei dem SemaphoreEnter immer aussteigt. Das Semaphore scheint irgendwie gar nicht mehr aufgeräumt zu werden.

Nehme ich dann die Semaphore-Zeilen raus, läuft das Script wieder.

Wo liegt mein Fehler ?

Fehler Nr1: Du hast nicht dein komplettes Skript geposted :stuck_out_tongue: :smiley:

Hier gibt es ein Beispiel, wie die Semaphore aussehen muss:
Hängende Threads durch simplexml_load_file()
…gibt aber auch noch viele andere Threads mit Beispielen.

Wichtig > Mit IF die Semaphore betreten und IM IF dann die Semaphore wieder verlassen. Und vlt. ist „1“ als Timeout auch etwas klein gewählt. Da bekommt dein Receiver gar keine Luft zum Atmen. Gibt ihm wenigstens mit „250“ die 250ms Zeit zum entspannen :slight_smile:

Grüße,
Chris

Hm, ich hatte mit daran gehalten:

https://www.symcon.de/forum/threads/28285-mehrfache-Ausf%C3%BChrung-von-Skripten-verhindern?highlight=mehrfache+ausf%FChrung

da ist das leave außerhalb von if und der timeout 1.

Ich probiere das aber auch mal gerne wie von dir vorgeschlagen. Magst du mir erklären, warum das Leave im IF von ENTER wichtig ist ? Bei mir scheint ja eher das Problem zu sein, dass das ENTER gar nicht geht und das Script daher aussteigt.

Ich frage da so hartnäckig nach, da das Probieren mühsam ist - der Fehler kommt so nach 4-5 Stunden.

Mein komplettes Script kann ich grad nicht posten, stelle es aber gerne später nochmal rein.

Das Leave muss 100% im IF sein! Ansonsten wird die Semaphore nie verlassen und ist so lange aktiv, wie das Skript läuft. Müssten eigentlich auch im Meldungen-Fenster der IPS-Console entsprechende Hinweise sein…

Schreib das Leave in das IF und wenn ein Skript wirklich gar nicht warten soll, bis die Semaphore frei, dann kannst du die 1 lassen. Aber ich würde mir das so umbauen, dass maximal 2 Skripte gleichzeitig vom Timer her laufen können und die jeweils kurz warten, falls das andere Skript die Semaphore noch nicht freigegeben hat.

Weiß ja nicht was du genau vor hast, aber am Ende könnte man auch das Skript immer wieder sich selbst durch RunScript aufrufen lassen…aber dazu brauchen wir mehr Infos :slight_smile:

Und das Beispiel: https://www.symcon.de/forum/threads/28285-mehrfache-Ausführung-von-Skripten-verhindern?p=260543#post260543
…prüft ja nur, ob die Semaphore belegt ist. Da ist das Leave am Ende nur optional zum Aufräumen da. Wenn man aber die Semaphore betritt mit dem IF, dann muss INNERHALB dieses IF dann auch wieder ein Leave kommen, sonst wird die Semaphore nicht freigeben, wenn der Semaphoren-IF-Teil abgearbeitet ist.

Grüße,
Chris

Hm, hast du das „!“ auch berücksichtigt, das Paresy da rein gesetzt hat ? Von der Logik her ist es so, dass es sich dann beendet, wenn das Enter NICHT klappt. Ich glaube, dass stimmt dann mit deiner Logik überein, oder ?

Hier nun das Script:


<?
IPSUtils_Include ("IPSInstaller.inc.php","IPSLibrary::install::IPSInstaller");

if(!IPS_SemaphoreEnter("SR7007", 250 /* sehr kurz warten */)) {
 return; //Läuft bereits
}

$freq=array(
	"8760"=> "NDR 2",
	"8830"=> "RB Nordwest",
	"8980"=> "Energy Bremen",
	"9030"=> "NDR 903",
	"9110"=> "NDR 1",
	"9250"=> "Radio WeserTV",
	"9290"=> "NDR N-Joy",
	"9380"=> "RB Bremen",
	"9440"=> "NDR Kultur",
	"9500"=> "NDR Info",
	"9670"=> "WDR Funkhaus",
	"9760"=> "BFBS Germany",
	"9860"=> "NDR Info",
	"9920"=> "NDR Kultur",
	"9980"=> "NDR 2",
	"10030"=> "DLF Kultur",
	"10120"=> "RB Bremen",
	"10170"=> "Radio FFN",
	"10230"=> "Radio FFN",
	"10360"=> "Radio Hamburg",
	"10420"=> "Antenne Niedersachsen",
	"10480"=> "Antenne Niedersachsen",
	"10570"=> "Antenne Niedersachsen",
	"10620"=> "DLF Kultur",
	"10710"=> "DLF",
	"10760"=> "Radio 21",
);

switch ($_IPS['SENDER']){
case 'Execute':
	CreateProfile_Switch       ('SR7007_Power','Aus', 'An', "", -1, 0x00ff00);
	@IPS_CreateVariableProfile('SR7007_Frequenz', 2);
	IPS_SetVariableProfileText('SR7007_Frequenz', '', ' MHz');
	IPS_SetVariableProfileValues('SR7007_Frequenz', 0, 2000, 0.1);
	IPS_SetVariableProfileDigits('SR7007_Frequenz', 2);
	IPS_SetScriptTimer($_IPS['SELF'],10);
	break;
case 'TimerEvent':
	$t=microtime(true);
	CSCK_SendText(52404 /*[Marantz SR7007]*/,"PW?".chr(13));
	usleep(100);
	CSCK_SendText(52404 /*[Marantz SR7007]*/,"ZM?".chr(13));
	usleep(100);

	CSCK_SendText(52404 /*[Marantz SR7007]*/,"Z2?".chr(13));
	usleep(100);
	CSCK_SendText(52404 /*[Marantz SR7007]*/,"Z2MU?".chr(13));
	usleep(100);
	CSCK_SendText(52404 /*[Marantz SR7007]*/,"Z2CS?".chr(13));
	usleep(100);
	CSCK_SendText(52404 /*[Marantz SR7007]*/,"Z2CV?".chr(13));
	usleep(100);

	CSCK_SendText(52404 /*[Marantz SR7007]*/,"MV?".chr(13));
	usleep(100);
	CSCK_SendText(52404 /*[Marantz SR7007]*/,"SI?".chr(13));
	usleep(100);
	CSCK_SendText(52404 /*[Marantz SR7007]*/,"MS?".chr(13));
	usleep(100);
	CSCK_SendText(52404 /*[Marantz SR7007]*/,"DC?".chr(13));
	usleep(100);
	CSCK_SendText(52404 /*[Marantz SR7007]*/,"PSMODE: ?".chr(13));
	usleep(100);
	CSCK_SendText(52404 /*[Marantz SR7007]*/,"TFAN?".chr(13));
	usleep(100);
	CSCK_SendText(52404 /*[Marantz SR7007]*/,"ST?".chr(13));
	IPS_SetScriptTimer($_IPS['SELF'],4+ceil(microtime(true)-$t));
	break;
case 'RegisterVariable':
//   choe"SR7007: Empfange...
";
    // bereits im Puffer der Instanz vorhandene Daten in $data kopieren
    $data  = RegVar_GetBuffer($_IPS['INSTANCE']);
    // neu empfangene Daten an $data anhängen
    $data .= $_IPS['VALUE'];

    // wenn das Trennzeichen ; in $data gefunden worden ist
    if (strpos($data, chr(13)))
    {
        // $data in durch ; separierte Datensätze zerlegen
        $datasets = explode(chr(13), $data);

        // alle nicht durch ; terminierten Datensätze ausgeben
        for ($i = 0; $i < count($datasets) - 1; $i++)
        {
				if (strpos($datasets[$i],"PWON")===0){
				   setvalue(CreateVariable("Power", 0, IPS_GetParent($_IPS['SELF']), 0, "SR7007_Power"),true);
				}
				elseif (strpos($datasets[$i],"PWSTANDBY")===0){
				   setvalue(CreateVariable("Power", 0, IPS_GetParent($_IPS['SELF']), 0, "SR7007_Power"),false);
				}
				elseif (strpos($datasets[$i],"ZMON")===0){
				   setvalue(CreateVariable("Main Zone", 0, IPS_GetParent($_IPS['SELF']), 0, "SR7007_Power"),true);
				}
				elseif (strpos($datasets[$i],"ZMOFF")===0){
				   setvalue(CreateVariable("Main Zone", 0, IPS_GetParent($_IPS['SELF']), 0, "SR7007_Power"),false);
				}
				elseif (strpos($datasets[$i],"Z2ON")===0){
				   setvalue(CreateVariable("Zone 2", 0, IPS_GetParent($_IPS['SELF']), 0, "SR7007_Power"),true);
				}
				elseif (strpos($datasets[$i],"Z2OFF")===0){
				   setvalue(CreateVariable("Zone 2", 0, IPS_GetParent($_IPS['SELF']), 0, "SR7007_Power"),false);
				}
				elseif (preg_match('/^Z2([0-9]+)/',$datasets[$i],$result)){
				   setvalue(CreateVariable("Zone 2 Volume", 1, IPS_GetParent($_IPS['SELF']), 0),$result[1]);
				}
				elseif (preg_match('/^MV([0-9]+)/',$datasets[$i],$result)){
				   setvalue(CreateVariable("Master Volume", 1, IPS_GetParent($_IPS['SELF']), 0),(substr($result[1]."0",0,3)/10));
				}
				elseif (preg_match('/^MVMAX ([0-9]+)/',$datasets[$i],$result)){
				echo "SR7007: ".$datasets[$i]."
";
				   setvalue(CreateVariable("Master Volume Max", 1, IPS_GetParent($_IPS['SELF']), 0),(substr($result[1]."0",0,3)/10));
				}
				elseif (preg_match('/^SI(.+)/',$datasets[$i],$result)){
				   setvalue(CreateVariable("Main Zone Audio Input", 3, IPS_GetParent($_IPS['SELF']), 0),$result[1]);
				}
				elseif (preg_match('/^SV(.+)/',$datasets[$i],$result)){
				   setvalue(CreateVariable("Main Zone Video Input", 3, IPS_GetParent($_IPS['SELF']), 0),$result[1]);
				}

				elseif (strpos($datasets[$i],"PSDCO ON")===0){
				   setvalue(CreateVariable("Main Zone D.COMP", 0, IPS_GetParent($_IPS['SELF']), 0, "SR7007_Power"),true);
				}
				elseif (strpos($datasets[$i],"PSDCO OFF")===0){
				   setvalue(CreateVariable("Main Zone D.COMP", 0, IPS_GetParent($_IPS['SELF']), 0, "SR7007_Power"),false);
				}
				elseif (preg_match('/^PSDRC (.+)/',$datasets[$i],$result)){
				   setvalue(CreateVariable("Main Zone DRC direct change", 3, IPS_GetParent($_IPS['SELF']), 0),$result[1]);
				}
				elseif (preg_match('/^PSLFE ([0-9]+)/',$datasets[$i],$result)){
				   setvalue(CreateVariable("Main Zone LFE", 1, IPS_GetParent($_IPS['SELF']), 0),$result[1]);
				}
				elseif (preg_match('/^PSBAS ([0-9]+)/',$datasets[$i],$result)){
				   setvalue(CreateVariable("Main Zone Bass", 1, IPS_GetParent($_IPS['SELF']), 0),$result[1]);
				}
				elseif (preg_match('/^PSTRE ([0-9]+)/',$datasets[$i],$result)){
				   setvalue(CreateVariable("Main Zone Trebble", 1, IPS_GetParent($_IPS['SELF']), 0),$result[1]);
				}
				elseif (strpos($datasets[$i],"PSTONE CTRL OFF")===0){
				   setvalue(CreateVariable("Main Zone Tone Control", 0, IPS_GetParent($_IPS['SELF']), 0, "SR7007_Power"),false);
				}

				elseif (strpos($datasets[$i],"Z2MUON")===0){
				   setvalue(CreateVariable("Zone 2 Mute", 0, IPS_GetParent($_IPS['SELF']), 0, "SR7007_Power"),true);
				}
				elseif (strpos($datasets[$i],"Z2MUOFF")===0){
				   setvalue(CreateVariable("Zone 2 Mute", 0, IPS_GetParent($_IPS['SELF']), 0, "SR7007_Power"),false);
				}
				elseif (strpos($datasets[$i],"Z2CSST")===0){
				   setvalue(CreateVariable("Zone 2 Channel Setting", 3, IPS_GetParent($_IPS['SELF']), 0),"STEREO");
				}
				elseif (strpos($datasets[$i],"Z2CSMONO")===0){
				   setvalue(CreateVariable("Zone 2 Channel Setting", 3, IPS_GetParent($_IPS['SELF']), 0),"MONO");
				}
				elseif (preg_match('/^Z2CVFL ([0-9]+)/',$datasets[$i],$result)){
				   setvalue(CreateVariable("Zone 2 Front L Level", 1, IPS_GetParent($_IPS['SELF']), 0),$result[1]);
				}
				elseif (preg_match('/^Z2CVFR ([0-9]+)/',$datasets[$i],$result)){
				   setvalue(CreateVariable("Zone 2 Front R Level", 1, IPS_GetParent($_IPS['SELF']), 0),$result[1]);
				}
				elseif (preg_match('/^Z2(.+)/',$datasets[$i],$result)){
				   setvalue(CreateVariable("Zone 2 Input", 3, IPS_GetParent($_IPS['SELF']), 0),$result[1]);
				}
				elseif (preg_match('/^MS(.+)/',$datasets[$i],$result)){
				   setvalue(CreateVariable("Main Zone Surround Mode", 3, IPS_GetParent($_IPS['SELF']), 0),$result[1]);
				}
				elseif (preg_match('/^DC(.+)/',$datasets[$i],$result)){
				   setvalue(CreateVariable("Main Zone Decode Mode", 3, IPS_GetParent($_IPS['SELF']), 0),$result[1]);
				}
				elseif (preg_match('/^PSMODE:(.+)/',$datasets[$i],$result)){
				   setvalue(CreateVariable("Main Zone Sourround Mode", 3, IPS_GetParent($_IPS['SELF']), 0),$result[1]);
				}

				elseif (preg_match('/^TFAN([0-9]{6})/',$datasets[$i],$result)){
					if (!($disp=$freq[(int)$result[1]])) $disp=$result[1]/100;
				   setvalue(CreateVariable("Tuner Frequenzy", 2, IPS_GetParent($_IPS['SELF']), 0, 'SR7007_Frequenz'),$result[1]/100);
				   setvalue(CreateVariable("Tuner Display", 3, IPS_GetParent($_IPS['SELF']), 0, 'SR7007_Frequenz'),$disp);
				}
				elseif (substr($datasets[$i],0,1)!="@"){
	            echo "SR7007: ".$datasets[$i]."
";
				}
//				else{
//	            echo "SR7007: ".$datasets[$i]."
";
//				}
        }
        // $data auf den Inhalt des letzten (unvollständigen) Datensatzes setzen
        $data = $datasets[count($datasets) - 1];
    }

    // Inhalt von $data im Puffer der RegisterVariable-Instanz speichern
    RegVar_SetBuffer($_IPS['INSTANCE'], $data);
	break;
case 'Designer':
   if (strpos($_IPS['COMPONENT'],'SR7007WZ')===0){
		CSCK_SendText(52404 /*[Marantz SR7007]*/,(getvalue(59978 /*[sr7007 Wohnzimmer\Main Zone]*/  )?"ZMOFF":"ZMON").chr(13));
		CSCK_SendText(52404 /*[Marantz SR7007]*/,"SICD".chr(13));
   }

   elseif (strpos($_IPS['COMPONENT'],'SR7007ZMPWR')===0){
		CSCK_SendText(52404 /*[Marantz SR7007]*/,(getvalue(59978 /*[sr7007 Wohnzimmer\Main Zone]*/  )?"ZMOFF":"ZMON").chr(13));
   }
   elseif (strpos($_IPS['COMPONENT'],'SR7007ZMVOLP')===0){
		CSCK_SendText(52404 /*[Marantz SR7007]*/,"MVUP".chr(13));
   }
   elseif (strpos($_IPS['COMPONENT'],'SR7007ZMVOLM')===0){
		CSCK_SendText(52404 /*[Marantz SR7007]*/,"MVDOWN".chr(13));
   }
   elseif (strpos($_IPS['COMPONENT'],'SR7007ZMISTUNER')===0){
		CSCK_SendText(52404 /*[Marantz SR7007]*/,"SITUNER".chr(13));
   }
   elseif (strpos($_IPS['COMPONENT'],'SR7007ZMISC3PO')===0){
		CSCK_SendText(52404 /*[Marantz SR7007]*/,"SISAT/CBL".chr(13));
   }
   elseif (strpos($_IPS['COMPONENT'],'SR7007ZMISCD')===0){
		CSCK_SendText(52404 /*[Marantz SR7007]*/,"SICD".chr(13));
   }
   elseif (preg_match('/^SR7007ZMVOL([0-9]+)/',$_IPS['COMPONENT'],$result)){
		CSCK_SendText(52404 /*[Marantz SR7007]*/,"MV".$result[1].chr(13));
   }

   elseif (strpos($_IPS['COMPONENT'],'SR7007Z2PWR')===0){
		CSCK_SendText(52404 /*[Marantz SR7007]*/,(getvalue(25155 /*[sr7007 Wohnzimmer\Zone 2]*/ )?"Z2OFF":"Z2ON").chr(13));
   }
   elseif (strpos($_IPS['COMPONENT'],'SR7007Z2VOLP')===0){
		CSCK_SendText(52404 /*[Marantz SR7007]*/,"Z2UP".chr(13));
   }
   elseif (strpos($_IPS['COMPONENT'],'SR7007Z2VOLM')===0){
		CSCK_SendText(52404 /*[Marantz SR7007]*/,"Z2DOWN".chr(13));
   }
   elseif (preg_match('/^SR7007Z2VOL([0-9]+)/',$_IPS['COMPONENT'],$result)){
		CSCK_SendText(52404 /*[Marantz SR7007]*/,"Z2".$result[1].chr(13));
   }
   elseif (preg_match('/^SR7007MS(.+)/',$_IPS['COMPONENT'],$result)){
		CSCK_SendText(52404 /*[Marantz SR7007]*/,"MS".str_replace("_"," ",$result[1]).chr(13));
   }
	break;
case 'Variable':
   if ($_IPS['VARIABLE']==37778 /*[sr7007 Wohnzimmer\Command]*/){
      $cmdarr=explode(";",$_IPS['VALUE']);
		for ($i=0;$i<count($cmdarr);$i++){
			CSCK_SendText(52404 /*[Marantz SR7007]*/,$cmdarr[$i].chr(13));
			usleep(100000);
		}
   }
	break;
default:
   setvalue(25074 /*[sr7007 Wohnzimmer\Debug]*/,$_IPS['SENDER']);
	break;
}
Aufräumen. Falls das Skript vorher stirbt, gibt es eine weitere Fehlermeldung, aber die Semaphore wird trotzdem aufgeräumt!
IPS_SemaphoreLeave("SR7007");

function SR7007_Input($value){
	$arr=IPS_GetVariableProfile("SR7007_Input")['Associations'];
	$ret=false;
	for ($i=0;$i<count($arr);$i++){
		if ($arr[$i]['Name']==$value){
		   $ret=$i;
		}
	}
	return $ret;
}
?>

für weitere Anregungen insb. mit dem RunScript bin ich sehr dankbar ! Das Script läut super und auch stabil, wenn die Semaphore-Geschichte nicht drin ist. Jedoch kann es sein, dass es dann die Threads blockiert.

Mit dem Semaphore läuft es auch - aber dann nur einige Stunden stabil. Danach greift offenbar der ENTER nicht mehr und lässt das Script nur noch vorzeitig abbrechen (Ausstieg beim SemaphoreEnter)

Öhm…ich will ja nichts sagen, aber dein Skript nutzt keine Semaphore :slight_smile: Es prüft nur, ob eine Semaphore gesetzt ist, was aber in diesem Skript NIE passiert :wink:

Das ! bedeutet quasi „== false“…also zu gut deutsch > wenn das Skript nicht in die Semaphore kommt innerhalb 250ms, dann beenden…aber es gibt keine Semaphore…deshalb hast du wohl auch keine Verbesserung mit dem Crashs :wink:

Wie man eine Semaphore richtig betritt und verlässt hab ich dir verlinkt.

Du musst eine Semaphore betreten, dann den Code schreiben, der innerhalb der Semaphore laufen soll, dann die Semaphore mit „Leave“ verlassen und fertig. Die 250ms bedeuten, so lange soll ein anderes Skript warten, falls die Semaphore belegt ist und dann den IF-Teil „überspringen“.

Bitte korrigiert mich, wenn ich totalen Mist erzähle :smiley: Aber ich verwende Semaphore schon immer so wie beschrieben und so funktioniert es bei mir auch in mehreren Projekten ohne Problem :slight_smile:

Grüße,
Chris

sicher ? Ich verstehe das so:

if(!IPS_SemaphoreEnter("SR7007", 250 /* sehr kurz warten */)) { 
 return; //Läuft bereits 
} 

Das Semaophore wird gesetzt. Schlägst das aber fehl, wird der Ausstieg erzwungen (return)
danach müsste es gesetzt sein…

Absolut Korrekt.

Eventuell hilft es einfach mal anstatt einer globale Semaphore für das ganze Script, diese nur auf Teile zu beziehen.

Also eine Semaphore für den Datenempfang (case ‚RegisterVariable‘). Wobei ich meine dort brauchst du keine, weil die RegVar Thread-Safe ist.

Und eine Semaphore für alle Schaltbefehle, wo du mit CSCK_SendText Daten versendest.
Wobei auch das eigentlich egal sein sollte… das sind so wenig Daten, die passen immer in ein Ethernet-Frame, so das auch der ClientSocket die Daten immer am Stück versenden sollte ohne sie zu ‚vermischen‘ wenn du Zeitgleich CSCK_SendText ausführst.

Ist der Receiver so lahm, das die auch immer einen Sleep brauchst ?

Das Onkyo Protokoll ist ja fast genauso aufgebaut, da klappt das bei mir auch so.

Den Hänger könnte ich mir dadurch erklären, dass die RegVar permanent das Script triggert und dann die 250ms einfach zu lang sind.

Michael

Naja nicht total, aber zu behaupten

dein Skript nutzt keine Semaphore :slight_smile: Es prüft nur, ob eine Semaphore gesetzt ist,
wenn darin der Befehl IPS_SemaphoreEnter ausgeführt wird, ist schon etwas mißdeutend :confused:

Siehe auch die Abwehrdiskussion des IPS-Teams zu verbesserten Methoden zur Ablauf-Absicherung.

Viele Grüsse
Harald

Wie gesagt, ich war der Meinung (und verwende es auch überall ohne Probleme in meinen Projekten so), dass die Semaphore so zu verwenden ist, wie im von mir verlinkten und erwähnten Beispiel mit SemaphoreEnter ohne „!“ und das Leave dann im IF…

Semaphore hatte für mich den Sinn bestimmten Code „einmalig“ (halt in einer Semaphore) auszuführen…ich war nie auf die Idee gekommen, und sehe auch denn Sinn nicht, ein komplettes Skript durch eine Semaphore zu jagen/schützen.

Aber wenn Muddi Nall chan es sagt, dann ist es so :slight_smile: Er ist der Meister und ich eher so der Padawan :smiley: :wink:

Und die andere Diskussion ging irgendwie an mir vorbei :slight_smile:

Grüße,
Chris

Es ist völlig egal wie ihr es nutzt.
Beide Varianten gehen.
Wichtig ist nur dass das Leave dann auch an der richtigen Stelle steht :slight_smile:

Ich nutze auch eher die ‚nicht‘ Variante und steige dann aus.
Wurde sie erfolgreich gesetzt, kommt an Ende immer das Leave.

Oder halt die ‚true‘ Variante, dann kommt das Leave halt im Block der Abfrage.

Eine reine ‚nur schauen ob Semaphore gesetzt‘ gibt es nicht. Enter setzt sie dann, wenn noch nicht belegt :slight_smile:

Michael

Du sagst zwar es ist egal wie man es nutzt, aber wenn du eher die „!“ Variante verwendest, hat das doch sicher einen Grund?! :slight_smile:

Magst du es vlt noch ein wenig genauer erläutern?

Ich nutze ja nur die IF Variante mit dem Code-Block und wenn das eher suboptimal ist, dann lerne ich gern dazu. Will den Usern ja nichts suboptimales in meinen Projekten zumuten :slight_smile:

Danke und Grüße,
Chris

Der Grund ist einfach die Art wie / wo du Semaphore nutzt.
Und wie du deinen Code aufbaust.
Ich versuche mir gerade krampfhaft alle Verschachtelungen ab zu gewöhnen und durch kleiner Funktionen oder durch umbauen der Abfragen ab zu gewöhnen.
Michael

Hmmm…ok… Werd mir meine Projekte nochma anschauen und versuchen (mit dem neuen Wissen) zu erkennen was wo sinnvoller ist :slight_smile: Danke!

Allgemein versuche ich meinen Code möglichst so zu schreiben, dass er für andere möglichst einfach/schnell nachvollziehbar ist. Wo ich schon so wenig im Code dokumentiere :smiley:
Weil SOLLTE ich irgendwann nicht mehr aktiv sein, sollen andere alles easy weiter nutzen oder erweitern können. Und wenn ich dafür ein paar mehr Zeile brauche, dann ist das halt so. Hauptsache möglichst gut lesbar aber trotzdem funktionell :slight_smile:
…sofern möglich :smiley: Immer geht es ja auch nicht…

-Chris-

Naja, ich habe keinen besonderen schlauen Grund, es so zu machen. Ich habe STRG+C und STRG+V benutzt, nachdem Paresy es mir in seinem Thread so empfohlen hatte. Mein Ziel war es ja nur, den mehrfachen Aufruf zu verhindern.

Zurück zum Problem:
Gestern Abend gegen 18 Uhr hatte ich das Script wieder mit Semaphore angeworfen, Timeout 1000ms und zyklisch alle 5s. Gegen Mitternacht war Schluss, danach konnte das Semaphore nie wieder gesetzt werden.

Wenn ich dann manuell ein SemaphoreLeave extra ausführe, läuft es wieder (für ein paar Stunden)

Kann es sein, dass man beim Fehlschlag des SemaphoreEnter noch extra ein Leave ausführen muss? Mir scheint es so, dass das automatische Aufräumen des Leave in diesem Fall einfach nicht funktioniert oder länger dauert als der zyklische Aufruf ihm Zeit lässt. Ich werde jetzt mal warten, bis das Problem wieder auftritt und dann das zykl. Eregnis wegnehmen. Dann werde ich sehen, ob der Leave später austomatisch kommt.

Oder, Chris, wäre es denn sinnvoller, so ein zyklisches Pollen anders zu machen? Du hast ja mal angedeutet, dass mit RunScript evtl. die ganze Sache sinnvoller wäre.

Hm, es ist komplizierter …

das hat irgendwas auch etwas mit dem CSCK Befehlen zu tun.

Neuer Test:
Die Semaphore waren drin. Irgendwann können die Semaphore aber nicht gesetzt werden - wenn ich dann den Receiver aus- und wieder einschalte, geht es wieder.

Also irgendwie verhindert wohl diese Client Socket Geschichte das mit den Semaphores - irgendwas „hängt“ da. Das kann natürlich auch irgendein Problem des Receivers sein, der irgendwo nicht sauber kommuniziert.

Moin!

Ich mache es in einem aktuellen Projekt so:

<?
$PollingAktiv = GetValue(12345);  // Bool-Variable zum Aktivieren/Deaktivieren des Poll

if ($PollingAktiv === false)
{
	return;
}


if (IPS_SemaphoreEnter("BLABLA", 15*1000))
{
		//Hier steht einiges an Code
		//Befehl bla
		//Abfrage blubb
		
		if ($PollingAktiv === true)
		{
			IPS_RunScript($_IPS['SELF']);
		}
		IPS_SemaphoreLeave("BLABLA");
}
?>

Damit hast du quasi eine Endlosschleife (sofern du alle möglichen Fehlerfälle im Skript sauber abfängst :wink: Das ist wichtig, sonst beendet sich der ganze Konstrukt und es werden keine Daten mehr gepollt), welche durch Schalten der Bool-Variable 12345 angehalten und gestartet werden kann. Bei Bool FALSE muss man nichts weiter machen im Action-Skript, bei TRUE muss man einfach nur ein RunScript für das Script einsetzen.

So laufen immer nur maximal 2 (oder wenn mal was schief läuft für kurze Zeit 3) Skripte. Damit ist sichergestellt, dass immer ein Skript Daten pollt. So die Theorie und auch die Praxis-Tests der letzten Tage.

Grüße,
Chris

Zuerst würde ich mir mal den Debug des Socket ansehen.
Musst du pollen ? Sendet das Gerät nicht Änderungen von alleine ?
Und hast du mal die Ansicht mit den laufenden PHP-Threads geöffnet ?
Vielleicht hängt dort ein Thread von diesem Script, weshalb die Semaphore ebenfalls nicht beendet wird.
Michael
PS: Welche IPS-Version ?

@Chris:

danke, das ist auf jeden Fall ein interessanter Ansatz. Jedoch kann ich dann ja schlecht steuern, wie häufig das Script aufgerufen wird, oder ? Ich kann das ganze natürlich mit sleeps zeitlich dehnen, aber eigentlich läuft das Script dann ja immer. Mir erschließt sich dann nicht mehr der Sinn des Semaphore - wie kann sich das Script denn mehrfach laufen, wenn es sich brav immer nacheinander aufruft ?

@Nall chan

Zuerst würde ich mir mal den Debug des Socket ansehen.

okay, den kenne ich, da gehen die Daten über die RegVar ja rein und raus - worauf soll ich denn achten ?

Musst du pollen ? Sendet das Gerät nicht Änderungen von alleine ?

ja, LEIDER. Allerdings ist das auch Meckern auf hohem Niveau, Ich bin schon sehr dankbar, dass der Receiver überhaupt auf Anfragen die Statusinformationen raushaut. Dadurch kriege ich eine schöne Live-Ansicht des Receivers, wie er eingestellt ist.

Und hast du mal die Ansicht mit den laufenden PHP-Threads geöffnet ?

ja, da stehen 2 Threads dieses Scripts drin, wenn die Semaphore-Geschichte aktiv ist und die Sache läuft. Ohne Semaphore werden es mehr, da das Script auch durch Ereignisse ausgelöst wird. (Variablen oder Designer, die den Receiver steuern)

Vielleicht hängt dort ein Thread von diesem Script, weshalb die Semaphore ebenfalls nicht beendet wird.
Michael

okay, danach kann ich mal schauen. Gegenfrage: Bekomme ich dann irgendwie raus, WO das Script hängt ? Wenn ich nämlich im Script das Semaphore reinsetze, schnurrt die Sache sofort wieder.

PS: Welche IPS-Version ?

die letzte stabile 3.4, gerade Anfang der Woche gemacht.

Danke fürs Mitdenken und für die Anregungen !

Ich meinem Projekt polle ich in den 15 Sekunden rund 30 Mal eine WebAPI :smiley: Und die Semaphore habe ich deshalb, damit nicht mehrere Skripte gleichzeitig auf die WebAPI „losgehen“, sondern immer brav ein Skript nach dem anderen, aber immer ein Skript. Damit keine Daten „übersehen“ werden :slight_smile:

Wenn das nicht in diesem Ausmaß brauchst, dann einfach mit Sleep „ausbremsen“ :slight_smile:

Grüße,
Chris