Fragen zu IPS_SemaphoreEnter

Hallo Leute,

ich bin etwas unsicher bei der Deutung des Befehls „IPS_SemaphoreEnter“ bzw. „IPS_SemaphoreLeave“.

Wenn ich verhindern möchte, das eine Funktion mehrfach gleichzeitig ausgeführt wird, wendet man diesen Befehl dann innerhalb der Funktion an oder eher dort, wo die Funktion aufgerufen wird? (Die Funktion ist in einem anderen Skript)

Joachim

Hi Joachim,

spontan würde ich das in die Funktion (weil zentral) einbauen

Würde das auch in die Funktion einbauen oder eine eigene Funktion dafür schreiben - kommt drauf an, was Du machen möchtest. Eventuell solltest Du mal genauer beschreiben was Du eigentlich erreichen möchtest.

Habe das in der Library einige male in Verwendung:
zB in der AudioMax Steuerung, um zu verhindern, das 2 Befehle gleichzeitig verarbeitet werden oder auch in IPSShadowing bei der Ansteuerung von Beschattungselementen.

Hallo Andreas,

auch Dir Dank für Deine Einschätzung!

Ich habe hier einen CUNO im Einsatz um ein FS20-Empfänger zu steuern, aber eigentlich um die Stellmotoren der Heizkörper zu bewegen. Es gibt aber offensichtlich ein Problem, wenn zwei oder mehr Skripte gleichzeitg versuchen auf das Gerät zuzugreifen. Deswegen habe ich jetzt eine zentrale Funktion geschrieben, die die Datensendung übernehmen soll, aber doppelte bzw. mehrfache Zugriffe verhindern soll.

Mal sehen, ob der sporadisch auftretende Fehler damit behoben wird.

Joachim

Hallo Leute,

hier mal mein Skript bzw. die Funktion in der ich IPS_SemaphoreEnter genutzt habe:

//*************************************************************************************************************
// Sendet eine Nachricht über den Busware-LAN-Adapter (CUNO)
function CUNO_Sendung($CUNO_ID, $Sendung)
	{
   
	
	If (IPS_SemaphoreEnter("CUNO-Sendung", 5000))
		{
			SetValueString(IPS_GetVariableIDByName('AuxMessage', $CUNO_ID), "");
			$AuxMessage = "";
			
			$result = @RegVar_SendText($CUNO_ID, $Sendung);
			If ($result==false)
				{
				IPS_Sleep(1500);
				RegVar_SendText($CUNO_ID, $Sendung);
				}
         IPS_Sleep(500);
			$AuxMessage = GetValueString(IPS_GetVariableIDByName('AuxMessage', $CUNO_ID));

			//Semaphore wieder freigeben
		   IPS_SemaphoreLeave("CUNO-Sendung");
		}
	return $AuxMessage;
	}

Habe ich es so korrekt angewendet? Eigentlich möchte ich sicherstellen, dass nur eine Sendung zur Zeit angestossen wird, wenn die Sendung also nun gerade ausgeführt wird, dann soll der nächste „Anwärter“ etwas warten…

Joachim

Genau so ist es korrekt.

Zwei kleine Vorschläge:

  1. Verwende im Vergleich, ob eine Funktion korrekt durchgelaufen ist immer den Typsicheren vergleich (===). Ist in deinem Fall nicht ganz erforderlich, aber für die Zukunft eine gute Angewohnheit und bei Funktionen die auch z.B. Strings zurückliefern können wichtig.

  2. Warum nutzt du die temporäre Variable „AuxMessage“ und nicht den RegVar_SetBuffer/GetBuffer? Der RegVar Buffer ist wesentlich weniger Ressourcenaufwändig als die String Variable. Oder greifst du die String Variable noch von anderen Stellen ab?

paresy

Hallo paresy,

vielen Dank für Deine Tipps!

Das Ganze setzt ja auf die Skripte von Tommiauf (Tommi selbst verwendet in seinem Skript RegVar_SetBuffer/GetBuffer).

Ich habe aber immer wieder eine Fehlermeldung beim Senden (Warning: Socket Error # 10054 Connection reset by peer), das die Verbindung vom CUNO nicht angenommen wird.

Ich habe daher versucht alle Sendungen über diesen Weg zu „kanalisieren“, so dass sichergestellt ist, dass jeweils immer nur eine Sendung zur Zeit durchgeführt wird. Obwohl ich die Zeiten (m.E.) schon sehr großzügig eingestellt habe, kommt es immer mal wieder zu diesen Fehlermeldungen.
Nun habe ich derzeit erst einen Heizungs-Stellantrieb und ein FS20-Switch dran hängen, daher habe ich ein wenig Angst, weitere Stellantriebe darüber laufen zu lassen…

Joachim

Hallo Leute,

hier noch mal mein aktuelles Skript zu dem Thema:

//*************************************************************************************************************
// Sendet eine Nachricht über den Busware-LAN-Adapter (CUNO)
function CUNO_Sendung($CUNO_ID, $Sendung)
	{
   
	
	If (IPS_SemaphoreEnter("CUNO-Sendung", 5000))
		{
			SetValueString(IPS_GetVariableIDByName('AuxMessage', $CUNO_ID), "");
			$AuxMessage = "";
			
			$result = @RegVar_SendText($CUNO_ID, $Sendung);
			If ($result==false)
				{
				IPS_Sleep(1500);
				RegVar_SendText($CUNO_ID, $Sendung);
				}
         IPS_Sleep(500);
			$AuxMessage = GetValueString(IPS_GetVariableIDByName('AuxMessage', $CUNO_ID));

			//Semaphore wieder freigeben
		   IPS_SemaphoreLeave("CUNO-Sendung");
		}
	return $AuxMessage;
	}

Hier der Teil des Skriptes, in dem diesem Funktion aufgerufen wird:

// Stellwert senden
//Puffer löschen
CUNO_Sendung($reg, $StellmotorAdresseDaten."FF00
");

// Für die monatliche Entkalkungsfahrt den Regelwert manipulieren
If ((GetValueInteger($TagDesMonats) == 1) and (GetValueString($AktuelleUhrzeit) == "08:00"))
{
	$y = "FF";
}

//Wert senden
CUNO_Sendung($reg, $StellmotorAdresseDaten."26".$y."
");
//Anzeigen, wie viele Sekunden bis zur nächsten Sendung vergehen
$result = CUNO_Sendung($reg, "T11
");

Nach meinem Verständnis müsste es zwischen den „erlaubten“ Durchläufen doch eine gewisse „Zeitpuffer“ geben.
Wenn ich die IPS-Logger Zeitstempel der Fehlermeldungen anschaue, vergehen genau die 1500mSek (bei Fehler) + die 500mSek IPS-Sleep.
Ich verstehe nicht so richtig, wie es trotz der Zeitpuffer immer wieder sporadisch zu diesen Fehlermeldungen kommt…

Jemand eine Idee?

Joachim