Seite 1 von 1

mit Mutex ganze Module sperren/entsperren

Verfasst: 02.09.2014 21:07
von SBond
Hi Leute,

ist es möglich ganze Module zu sperren, wenn man mit Threads arbeitet? Mein Modul ist noch in Entwicklung, soll aber nur mit LinkedLists und Speicheradressen arbeiten (also keine Gadgets oder ähnliches). Da ein Modul unter anderem viele Prozeduren und Variablen enthalten kann, möchte ich dass immer nur ein Thread auf die Prozeduren eines Moduls zugreift. Da die Prozeduren auch untereinander im Modul aufgerufen werden können, weiß ich nicht genau wo sich die Unterbringung eines Mutex anbietet.

Reicht für so etwas ein im Modul globales Mutex aus? Könnte es Probleme verursachen, wenn LockMutex() mehrfach aufgerufen wird?
...und noch so eine kleine Nebenfrage.... ist ein Mutex 100% sicher oder könnte es vorkommen, dass mehrere Threads exakt zeitgleich einen Mutex sperren wollen und somit z.B. 2 Threads eine Routine bearbeiten, die eigentlich nur eine bearbeiten darf.

Durch meine Erfahrungen mit Threads (Abstürze, Instabilitäten und Deadlocks) bin ich sehr vorsichtig geworden. Allerdings lässt er sich in meinem Fall nicht vermeiden :(

Re: mit Mutex ganze Module sperren/entsperren

Verfasst: 02.09.2014 23:15
von STARGÅTE
Vorab:
Wenn du ein "ganzes Module" sperren willst, also mit einem Mutex den parallelenzugriff verhindern willst, dann ist es ja trivial gesagt quatsch überhaupt einen Thread in diesem Modul zu nutzen, da er ja dann eh Nacheinander läuft.

Nun zu deinen konkreten Fragen:
>> "Reicht für so etwas ein im Modul globales Mutex aus?"

Nein, aus dem einfachen Grund, da es ja dann kein Sinn macht einen Thread zu nutzen.
>> "Könnte es Probleme verursachen, wenn LockMutex() mehrfach aufgerufen wird?"
Das ist leider nicht sicher. So kommt es durchaus zu unterschiedlichen Verhalten je nach Betriebssystem.
Unter Windows musst du dann zB genauso viele Unlocks im Thread aufrufen wie Locks damit an anderer Thread wieder arbeitet:

Code: Alles auswählen

Global Mutex = CreateMutex()

Procedure Test(Void)

	LockMutex(Mutex)
	
	Debug "Procedure"
	
	UnlockMutex(Mutex)
	
EndProcedure


Debug "Lock Main"
LockMutex(Mutex)

CreateThread(@Test(), 0)

Delay(100)

Debug "Lock Main"
LockMutex(Mutex)

Delay(100)

Debug "Unlock Main"
UnlockMutex(Mutex)

Delay(100)

Debug "Unlock Main"
UnlockMutex(Mutex)

Delay(100)
Ich glaube unter Linux ist das anders.

>> "ist ein Mutex 100% sicher?"
Ja!

Nachtrag:
Wenn du mit Listen arbeiten willst, kannst du für den Thread auch eine Pointer-Liste zur echten Liste erstellen.
So kann der Thread seine eigene Liste durchlaufen dann aber auf die selben Elemente zugreifen.
Je nachdem was du dann genau machst, musst du dann nur den Element-Zugriff selbst sichern.
Leider kann man nicht "mach mal meine Thread sicher" aufrufen. Leider ist man dazu gezwungen, sich sehr intensiv mit der Dynamik des Codes zu befassen, um günstige Stellen zu finden, an denen man Locked und Unlocked.

Wenn du im Main ein Element löschst, darf der Thread natürlich nicht gerade drauf zugreifen -> Absturtz.
Try&Error geht beim einbauen von Lock/Unlock auch nicht -> Instabilitäten
Mutex sollten auch wenns geht nicht vor einer Intensiven Berechnung gesperrt werden, da ja dann alles andere auf die Berechnung wartet. LockMutex also lieber in der Schleife, statt außen.
So kannst du bei Listen zB auch mit PushListPosition() und PopListPosition() arbeiten umd die Elemente zu merken.

Re: mit Mutex ganze Module sperren/entsperren

Verfasst: 02.09.2014 23:58
von NicTheQuick
STARGÅTE hat geschrieben:Ich glaube unter Linux ist das anders.
Falsch. Auch unter Linux funktioniert ein Mutex wie ein ReentrantLock. Also ein einzelner Thread kann mehrmals nacheinander locken, muss dann aber auch gleich oft wieder unlocken, damit andere Threads wieder sperren können. Dieses Verhalten ist beabsichtigt um zum Beispiel Rekursion einfacher zu machen.

Meiner Meinung reicht ein globaler Mutex innerhalb des Modules aus. Ich finde auch nicht, dass das falsch ist. Das kann durchaus seine Berechtigung haben. Außerhalb des Moduls können ja dennoch jede Menge Threads existieren, die dieses Modul nutzen wollen. Aber wenn sie das nicht immer machen, dann tun sie ja vermutlich immer noch andere Dinge parallel.

Die einfachste Lösung ist folgende: Innerhalb des Moduls einmalig einen Modul-globalen Mutex erstellen. Und dann zu Beginn jeder Procedure einfach 'LockMutex()' und vor 'EndProcedure' und 'ProcedureReturn' ein 'UnlockMutex()' einfügen. Fertig. Das ist vergleichbar mit den 'synchronized'-Methoden in Java.

Re: mit Mutex ganze Module sperren/entsperren

Verfasst: 03.09.2014 00:01
von SBond
vielen Dank für deine ausführliche Antwort :)

STARGÅTE hat geschrieben:Wenn du ein "ganzes Module" sperren willst, also mit einem Mutex den parallelenzugriff verhindern willst, dann ist es ja trivial gesagt quatsch überhaupt einen Thread in diesem Modul zu nutzen, da er ja dann eh Nacheinander läuft.
Der Thread selber läuft nicht im Modul, sondern außerhalb. So ist meine aktuelle konfiguration....
Ein Thread liest etwa 10 mal pro Sekunde Daten aus von einer seriellen Schnittstelle (ca. 60KB/s). Da selbst mit dem EventTimer und BindEvent ein Pufferüberlauf nicht verhindert werden kann, bin ich leider gezwungen einen Thread zu verwenden. Die gelesenen Daten werden nun an meinem Modul weitergeleitet. Das Modul hat die Aufgabe verschiedene Puffer (in der Regel FIFO-Speicher/Ringpuffer) zu verwalten und verteilt diese Daten an bestimmte Speicher. Da ich verhindern will, dass der Hauptthread in diesem Moment Speicher ausließt, erstellt oder löscht, soll das Modul immer dann gesperrt, wenn ein Thread gerade damit arbeitet (oder andersherum).

Ich habe jetzt folgenden Ansatz eingebunden, aber noch nicht getestet: Jede public-Prozedur im Modul sperrt beim Aufruf den Mutex und gibt diesen beim Beenden der Prozedut wieder frei. Um zu verhindern, dass durch Prozeduraufrufe innerhalb des Moduls ein Mutex ausversehen mehrfach gesperrt oder entsperrt wird, nutze ich mit Hilfe eines Makros die Konstante: #PB_Compiler_Procedure. Diese gibt den Namen der aktuellen Prozedur zurück und wird beim Sperren des Mutex in eine Variable geschrieben. So kann nur die Prozedur den Mutex entsperren, die diesen auch gesperrt hat.

...ich werde sehen, ob alles Reibungslos funktioniert. Man muss immer genau aufpassen. ;)

Edit: ich war wohl wieder zu langsam :)

Re: mit Mutex ganze Module sperren/entsperren

Verfasst: 03.09.2014 00:12
von STARGÅTE
@Nic: Alles klar. Das mit der Rekursion stimmt natürlich.
Allerdings gabs dafür unter Windows den "Bug" dass ich mit Thread_1 einen Mutex sperren kann und in Thread_2 (wenn dort kein LockMutex war) den Mutes wieder entsperren kann (obwohl es ein anderer Thread ist).
Hier die Diskussion von damals: http://www.purebasic.fr/german/viewtopi ... 75#p302875

@SBond: Nic hat ja davor deine Idee selbst vorgeschlagen, also ok.

Re: mit Mutex ganze Module sperren/entsperren

Verfasst: 03.09.2014 00:17
von SBond
ja stimmt :)

nochmals danke und eine gute Nacht :mrgreen: