Mehrfaches Lock-/UnlockMutex im selben thread
Verfasst: 15.03.2019 22:56
Offenbar kann man LockMutex und UnlockMutex innerhalb des gleichen Threads mehrmals aufrufen.
(btw: Das geht aus der Hilfe leider nicht so richtig hervor. Könnte man noch mit aufnehmen)
Ich habe einige Prozeduren, die verschachtelt sind, aber ggf. auch separat aufgerufen werden. Von daher sperrt sich jede Prozedur selbst mittels Lock/UnlockMutex. Das geht soweit gut, auch wenn sich mehrere dieser Prozeduren mehrfach selbst aufrufen.
Wenns dann irgendwo aber mal hängt suche ich nach einer Debuggermöglichkeit, um die Stelle herauszufinden wo evtl. ein Unlock vergessen wurde. Die Debuggerfunktionen und Hilfsfenster habe ich ehrlich gesagt bisher nicht so richtig bis in die Tiefe genutzt. Gibt das der Debugger her, dass man solche Fehler schnell auffindet?
In meinem Fall ist es leider nicht so, dass man das Problem einfach so nachstellen kann. Hier wird ein Customgadget (module) sowohl von einem thread "bedient" als auch gleichzeitig manuell über die GUI von mir. Und irgendwann gibts dann einen deadlock wo alles einfriert. Eine manuelle Fehlersuche wird an der Stelle zu einem ziemlichen rumstochern.
Nachtrag: Ich erweitere meine Frage mal etwas, da ich gerade ein Verständnisproblem habe
Es geht um ein Customgadget mit sagen wir mal folgenden Funktionen:
- Create
- Draw
- Free
Das Ganze ist in einem Module realisiert und die drei Prozeduren sind public.
Da das Customgadget mit mehreren Instanzen genutzt werden können soll, wird bei Create() intern eine Gadgetstruktur allokiert, in der alle nötigen Parameter gespeichert werden.
Das könnte z.B. so aussehen:
Wird das Gadget mittels Free() wieder entfernt, dann wird der allokierte Strukturspeicher dieser Instanz wieder freigegeben.
Nun hatte ich es so realisiert, dass ich pro Instanz einen Mutex angelegt habe, der die internen Prozeduren gegen Mehrfachaufruf schützen soll. Die öffentliche Funktion Draw() könnte ja von mehren Threads gleichzeitig für die selbe Gadgetinstanz aufgerufen werden.
Das hat nichts gebracht, es kam dabei trotzdem zum deadlock (irgendwann). Was mir einleuchtet ist, dass ich, um an den Mutex zu gelangen, erst einmal in die Struktur des betreffenden Gadget greifen muss.
Also so z.B.:
Das heißt, dass beim Griff in die Struktur bei LockMutex() die Struktur noch nicht geschützt ist. Wenn ein zweiter thread gerade das gleiche versucht, wird es krachen.
Daher dachte ich mir, dass ich für das gesamte Modul einen Globalen Mutex benutze.
Wie managed man das jetzt am besten, um unabhängig von den Instanzen des Customgadgets herauszubekommen, wann der Mutex wieder freigegeben werden muss? Und wann/wo erzeuge ich den Mutex?
Ich könnte je eine globale Init() und DeInit() Prozedur schreiben, die man vor Erzeugung der ersten Instanz bzw. nach Freigabe der letzten Instanz des Customgadgets aufrufen muss, aber das kommt mir zu ungeschmeidig vor.
Man könnte noch einen globalen Mutex-Zähler mitlaufen lassen, der in Create() und Free() jeweils angepasst wird. Aber ist das der richtige Weg, wenn man ein multiaufrufsicheres Customgadget schreiben möchte?
(btw: Das geht aus der Hilfe leider nicht so richtig hervor. Könnte man noch mit aufnehmen)
Ich habe einige Prozeduren, die verschachtelt sind, aber ggf. auch separat aufgerufen werden. Von daher sperrt sich jede Prozedur selbst mittels Lock/UnlockMutex. Das geht soweit gut, auch wenn sich mehrere dieser Prozeduren mehrfach selbst aufrufen.
Wenns dann irgendwo aber mal hängt suche ich nach einer Debuggermöglichkeit, um die Stelle herauszufinden wo evtl. ein Unlock vergessen wurde. Die Debuggerfunktionen und Hilfsfenster habe ich ehrlich gesagt bisher nicht so richtig bis in die Tiefe genutzt. Gibt das der Debugger her, dass man solche Fehler schnell auffindet?
In meinem Fall ist es leider nicht so, dass man das Problem einfach so nachstellen kann. Hier wird ein Customgadget (module) sowohl von einem thread "bedient" als auch gleichzeitig manuell über die GUI von mir. Und irgendwann gibts dann einen deadlock wo alles einfriert. Eine manuelle Fehlersuche wird an der Stelle zu einem ziemlichen rumstochern.
Nachtrag: Ich erweitere meine Frage mal etwas, da ich gerade ein Verständnisproblem habe
Es geht um ein Customgadget mit sagen wir mal folgenden Funktionen:
- Create
- Draw
- Free
Das Ganze ist in einem Module realisiert und die drei Prozeduren sind public.
Da das Customgadget mit mehreren Instanzen genutzt werden können soll, wird bei Create() intern eine Gadgetstruktur allokiert, in der alle nötigen Parameter gespeichert werden.
Das könnte z.B. so aussehen:
Code: Alles auswählen
*GraphGadget = AllocateStructure(GraphGadget)
If *GraphGadget <> 0
With *GraphGadget
\iGadgetX = x
\iGadgetY = y
\iGadgetHeight = iGadgetHeight
\iGadgetWidth = iGadgetWidth
\iGadgetBorderSize = iGadgetBorderSize
\iGadgetBorderColour = iGadgetBorderColour
... usw
Code: Alles auswählen
; Parametercheck
If *GraphGadget = 0
ProcedureReturn
EndIf
With *GraphGadget
; irgendwelche Aufräumarbeiten
EndWith
FreeStructure(*GraphGadget)
Das hat nichts gebracht, es kam dabei trotzdem zum deadlock (irgendwann). Was mir einleuchtet ist, dass ich, um an den Mutex zu gelangen, erst einmal in die Struktur des betreffenden Gadget greifen muss.
Also so z.B.:
Code: Alles auswählen
Procedure Draw(*GraphGadget.GraphGadget)
; Parametercheck
If *GraphGadget = 0 : ProcedureReturn : EndIf
; Wait until the Gadget is unlocked
LockMutex(*GraphGadget\iMutex)
; Mach was....
UnlockMutex(*GraphGadget\iMutex)
EndProcedureDaher dachte ich mir, dass ich für das gesamte Modul einen Globalen Mutex benutze.
Code: Alles auswählen
Global.i iMutexIch könnte je eine globale Init() und DeInit() Prozedur schreiben, die man vor Erzeugung der ersten Instanz bzw. nach Freigabe der letzten Instanz des Customgadgets aufrufen muss, aber das kommt mir zu ungeschmeidig vor.
Man könnte noch einen globalen Mutex-Zähler mitlaufen lassen, der in Create() und Free() jeweils angepasst wird. Aber ist das der richtige Weg, wenn man ein multiaufrufsicheres Customgadget schreiben möchte?