Aktuelle Zeit: 22.05.2019 18:53

Alle Zeiten sind UTC + 1 Stunde [ Sommerzeit ]




Ein neues Thema erstellen Auf das Thema antworten  [ 19 Beiträge ]  Gehe zu Seite 1, 2  Nächste
Autor Nachricht
 Betreff des Beitrags: Mehrfaches Lock-/UnlockMutex im selben thread
BeitragVerfasst: 15.03.2019 22:56 
Offline
Benutzeravatar

Registriert: 25.04.2006 17:29
Wohnort: Nähe Hamburg
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:
Code:
      *GraphGadget = AllocateStructure(GraphGadget)
      If *GraphGadget <> 0
         With *GraphGadget
            \iGadgetX = x
            \iGadgetY = y
            \iGadgetHeight = iGadgetHeight
            \iGadgetWidth = iGadgetWidth
            \iGadgetBorderSize = iGadgetBorderSize
            \iGadgetBorderColour = iGadgetBorderColour
            ... usw



Wird das Gadget mittels Free() wieder entfernt, dann wird der allokierte Strukturspeicher dieser Instanz wieder freigegeben.

Code:
      ; Parametercheck
      If *GraphGadget = 0
         ProcedureReturn
      EndIf
      
      With *GraphGadget
         ; irgendwelche Aufräumarbeiten
      EndWith
      
      FreeStructure(*GraphGadget)


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.:

Code:
   Procedure   Draw(*GraphGadget.GraphGadget)
      ; Parametercheck
      If *GraphGadget = 0 : ProcedureReturn : EndIf
      
      ; Wait until the Gadget is unlocked
      LockMutex(*GraphGadget\iMutex)
      
      ; Mach was....
      
      UnlockMutex(*GraphGadget\iMutex)
   EndProcedure


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.
Code:
Global.i iMutex

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?

_________________
"Never run a changing system!"
PB 5.62, OS: Windows 7 Pro x64, Desktopscaling: 125%, CPU: I7 6500, RAM: 16 GB, GPU: Intel Graphics HD 520
Ich bin Baujahr 1968, also aktuell 51.


Zuletzt geändert von Kurzer am 15.03.2019 23:28, insgesamt 2-mal geändert.

Nach oben
 Profil  
Mit Zitat antworten  
 Betreff des Beitrags: Re: Lock/UnlockMutex freezes per Debugger auffinden
BeitragVerfasst: 15.03.2019 23:04 
Offline
Kommando SG1
Benutzeravatar

Registriert: 01.11.2005 13:34
Wohnort: Glienicke
Kurzer hat geschrieben:
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.
Zumindest geht das solange gut, solange die Procedure (selbst) immer auch ein Unlock() ausführt und nicht etwa durch ein ProcedureReturn "frühzeitig" beendet wird.

Kurzer hat geschrieben:
Wenns dann irgendwo aber mal hängt suche ich nach einer Debuggermöglichkeit, um die Stelle herauszufinden wo evtl. ein Unlock vergessen wurde.
Du kannst dir ein Macro mit gleichem Namen schreiben, und dann in diesem Macro Quellcode Informationen abrufen:
#PB_Compiler_Line, #PB_Compiler_Procedure usw.
Diese können dann an eine eigene Procedure übergeben werden, die alle LockMutex() mitloggt und ggf. mit einem Counter prüft, in welcher Stufe es klemmt.

_________________
Bild
 
BildBildBild


Nach oben
 Profil  
Mit Zitat antworten  
 Betreff des Beitrags: Re: Lock/UnlockMutex freezes per Debugger auffinden
BeitragVerfasst: 15.03.2019 23:28 
Offline
Benutzeravatar

Registriert: 25.04.2006 17:29
Wohnort: Nähe Hamburg
STARGÅTE hat geschrieben:
Kurzer hat geschrieben:
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.
Zumindest geht das solange gut, solange die Procedure (selbst) immer auch ein Unlock() ausführt und nicht etwa durch ein ProcedureReturn "frühzeitig" beendet wird.

Ja, das ist auf jeden Fall gegeben. Das habe ich geprüft.

STARGÅTE hat geschrieben:
Du kannst dir ein Macro mit gleichem Namen schreiben, und dann in diesem Macro Quellcode Informationen abrufen:
#PB_Compiler_Line, #PB_Compiler_Procedure usw.
Diese können dann an eine eigene Procedure übergeben werden, die alle LockMutex() mitloggt und ggf. mit einem Counter prüft, in welcher Stufe es klemmt.

Das ist eine gute Idee, danke. :allright:

Allerdings habe ich meine Frage gerade per Edit ausgeweitet, evtl. "deadlockt" es ja aus anderen Gründen, weil ich die falsche Herangehensweise nutze? Evtl. kannst Du Dir mein Edit noch ansehen?

_________________
"Never run a changing system!"
PB 5.62, OS: Windows 7 Pro x64, Desktopscaling: 125%, CPU: I7 6500, RAM: 16 GB, GPU: Intel Graphics HD 520
Ich bin Baujahr 1968, also aktuell 51.


Nach oben
 Profil  
Mit Zitat antworten  
 Betreff des Beitrags: Re: Mehrfaches Lock-/UnlockMutex im selben thread
BeitragVerfasst: 15.03.2019 23:42 
Offline
Kommando SG1
Benutzeravatar

Registriert: 01.11.2005 13:34
Wohnort: Glienicke
Die Herangehensweise mit Create und Free ist verständlich, mache ich auch so.

Kurzer hat geschrieben:
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.
Hier stellt sich mit die Frage wieso das passieren sollte? CustonGadgets können mit BindEvent alle Events abfangen und auch nur genau bei diesen Events sich neu zeichnen. Von "außen" also public sollte der Draw() befehl eigentlich nicht ausgeführt werden. Wie auch immer kannst du natürlich den Draw mit einem Mutex schützen.
Deine Draw() Code sieht auch richtig aus.
Kurzer hat geschrieben:
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.
Nein, genau dafür sind ja Mutex, selbst wenn 1000 Threads die selbe Procedure aufrufen, wird nur einer "der Erste" sein und die Prozedur sperren, die anderen 999 warten dann bis die der andere Thread Unlock() aufruft.
Selbst wenn du innerhalb eines Threads Draw() verschachtelt aufrufst, und ggf. zwei mal Lockst, musst du auch zwei mal wieder unlocken, was ja automatisch gegeben ist.

Edit: hier noch eine weiterführende Information: https://www.purebasic.fr/german/viewtopic.php?p=302892#p302892

_________________
Bild
 
BildBildBild


Nach oben
 Profil  
Mit Zitat antworten  
 Betreff des Beitrags: Re: Mehrfaches Lock-/UnlockMutex im selben thread
BeitragVerfasst: 16.03.2019 00:56 
Offline
Benutzeravatar

Registriert: 25.04.2006 17:29
Wohnort: Nähe Hamburg
STARGÅTE hat geschrieben:
Die Herangehensweise mit Create und Free ist verständlich, mache ich auch so.

Okay, dann werde ich das wieder so umbauen, dass kein Globaler Mutex verwendet wird, sondern einer pro instanziertem Gadget.

STARGÅTE hat geschrieben:
Hier stellt sich mit die Frage wieso das passieren sollte? CustonGadgets können mit BindEvent alle Events abfangen und auch nur genau bei diesen Events sich neu zeichnen. Von "außen" also public sollte der Draw() befehl eigentlich nicht ausgeführt werden.

Okay, das war ein blödes Beispiel mit Draw().
Das Gadget, um das es geht, wird später eine bzw. mehrere Wellenformen bzw. mathematische Funktionen darstellen können. Quasi wie die Waveformanzeige bei einem Audioschnittprogramm.

Dafür gibt es dann öffentliche Funktionen, mit denen man dem Gadget einen darzustellenden Speicherblock mit einem Werte-Array zuweisen kann. Unter anderem kann man dann noch Farbe der Skalenbeschriftungen, Farbe der Wellenform und den Offset des Readpointers innerhalb des Speicherblocks setzen. Und erst, wenn man das alles gesetzt hat, dann kann man die Wellenform durch Aufruf von Update() anzeigen lassen. Es ist also Absicht, dass der User bestimmt, wann seine Wellenform im Gadget angezeigt wird.

STARGÅTE hat geschrieben:
Wie auch immer kannst du natürlich den Draw mit einem Mutex schützen.
Deine Draw() Code sieht auch richtig aus.

Danke für die Bestätigung der richtigen Vorgehensweise. Ich werde mir das morgen, nach dem Rückbau auf Instanzenbasierte Mutexe (also einen Mutex pro Instanz statt eines globalen Mutex), dann noch einmal genauer untersuchen.

STARGÅTE hat geschrieben:
Kurzer hat geschrieben:
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.
Nein, genau dafür sind ja Mutex, selbst wenn 1000 Threads die selbe Procedure aufrufen, wird nur einer "der Erste" sein und die Prozedur sperren, die anderen 999 warten dann bis die der andere Thread Unlock() aufruft.
Selbst wenn du innerhalb eines Threads Draw() verschachtelt aufrufst, und ggf. zwei mal Lockst, musst du auch zwei mal wieder unlocken, was ja automatisch gegeben ist.

Prima, dann war mein erster Ansatz ja eigentlich völlig richtig. Der Fehler muss also woanders liegen. Ich schau da morgen mit frischem Kopf weiter nach.

STARGÅTE hat geschrieben:
Edit: hier noch eine weiterführende Information: https://www.purebasic.fr/german/viewtopic.php?p=302892#p302892

Aha!!!

Freak schreibt dort:
Zitat:
Zitat:
Zitat:
If a thread calls LeaveCriticalSection when it does not have ownership of the specified critical section object, an error occurs that may cause another thread using EnterCriticalSection to wait indefinitely.

http://msdn.microsoft.com/en-us/library ... 85%29.aspx

Auf Deutsch: Ein Aufruf von UnlockMutex() aus dem falschen Thread kann dazu führen, dass ein anderer Thread bei LockMutex() hängenbleibt.

Ich ahne was mein Problem ist!
In meinem Testprogramm lasse ich vom Hauptthread zwei meiner Customgadgets erzeugen. Dann wird eines davon von einem Thread bedient und gleichzeitig von manuell von mir. Also aus der Hauptschleife bzw. der Ereignisschleife heraus.

Das heißt doch aber, dass die beiden Mutexe beide vom Hauptprogramm erzeugt worden sind. Keiner der Mutexe wurde vom thread erzeugt, der jetzt fleissig die Update() Prozedure des Gadgets befeuert.

Und da scheint jetzt genau das zu passieren, was Freak in seinem letzten Satz dort oben beschreibt.

Mist, wie löst man das denn? :freak:

_________________
"Never run a changing system!"
PB 5.62, OS: Windows 7 Pro x64, Desktopscaling: 125%, CPU: I7 6500, RAM: 16 GB, GPU: Intel Graphics HD 520
Ich bin Baujahr 1968, also aktuell 51.


Nach oben
 Profil  
Mit Zitat antworten  
 Betreff des Beitrags: Re: Mehrfaches Lock-/UnlockMutex im selben thread
BeitragVerfasst: 16.03.2019 10:00 
Offline
Kommando SG1
Benutzeravatar

Registriert: 01.11.2005 13:34
Wohnort: Glienicke
Wo der Mutex erstellt wird ist egal,
aber wenn Mutex#1 von Thread#1 gesperrt wird, darf nicht irgend ein anderer Thread genau diesen Mutex#1 wieder entsperren, sondern nur Thread#2

_________________
Bild
 
BildBildBild


Nach oben
 Profil  
Mit Zitat antworten  
 Betreff des Beitrags: Re: Mehrfaches Lock-/UnlockMutex im selben thread
BeitragVerfasst: 16.03.2019 11:56 
Offline
Benutzeravatar

Registriert: 20.04.2006 09:50
Kurzer hat geschrieben:
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).

Mit einem Mutex kannst du einen Deadlock nicht beheben oder verhindern, sondern lediglich überhaupt erst ermöglichen.

Bist du auch sicher, dass es ein Deadlock ist und nicht irgendeine Endlosschleife oder dergleichen?

Wenn ich mich richtig entsinne sind PB Mutexe reentrant, das heißt mehrfache Locks auf den selben Mutex im selben Thread werden 'durchgelassen' wenn der Lock bereits gesetzt ist. Das erfordert aber auch korrekte/balancierte Schachtellung von Lock/Unlock.
Einen Deadlock bekämst du z.B. wenn du nach einem Lock auf ein Signal von einem anderen Thread wartest, welcher seinerseits aber vor einem Lock auf den selben Mutex hängt und somit das Signal nie senden wird.

_________________
my pb stuff..
Bild..jedenfalls war das mal so.


Nach oben
 Profil  
Mit Zitat antworten  
 Betreff des Beitrags: Re: Mehrfaches Lock-/UnlockMutex im selben thread
BeitragVerfasst: 16.03.2019 12:13 
Offline
Benutzeravatar

Registriert: 25.04.2006 17:29
Wohnort: Nähe Hamburg
#NULL hat geschrieben:
Mit einem Mutex kannst du einen Deadlock nicht beheben oder verhindern, sondern lediglich überhaupt erst ermöglichen.
Bist du auch sicher, dass es ein Deadlock ist und nicht irgendeine Endlosschleife oder dergleichen?

Nein, sicher bin ich mir nicht. Ich versuche das Ganze mal auf ein kleines Testprogramm einzudampfen und schaue, ob das Problem da auch auftritt. Auf jeden Fall brauche ich sowas wie einen Mutex, weil mir der Code sonst abkackt, wenn zwei Threads gleichzeitig StartDrawing() aufrufen.

_________________
"Never run a changing system!"
PB 5.62, OS: Windows 7 Pro x64, Desktopscaling: 125%, CPU: I7 6500, RAM: 16 GB, GPU: Intel Graphics HD 520
Ich bin Baujahr 1968, also aktuell 51.


Nach oben
 Profil  
Mit Zitat antworten  
 Betreff des Beitrags: Re: Mehrfaches Lock-/UnlockMutex im selben thread
BeitragVerfasst: 16.03.2019 12:31 
Offline
Benutzeravatar

Registriert: 20.04.2006 09:50
Ich habe mal folgendes verwendet um dergleichen zu debuggen:
Code:
CompilerIf 0
 
  Procedure.s semaphoreName(s)
    Shared semaphoreMain, semaphoreDraw
    Select s
      Case semaphoreMain : ProcedureReturn "semaphoreMain"
      Case semaphoreDraw : ProcedureReturn "semaphoreDraw"
    EndSelect
  EndProcedure
 
  Procedure WaitSemaphore_proc(s)
    Debug "WaitSemaphore(" + semaphoreName(s) + ")"
    WaitSemaphore(s)
    Debug "WaitSemaphore(" + semaphoreName(s) + ") finished"
  EndProcedure
 
  Procedure SignalSemaphore_proc(s)
    Debug "SignalSemaphore(" + semaphoreName(s) + ")"
    SignalSemaphore(s)
    Debug "SignalSemaphore(" + semaphoreName(s) + ") finished"
  EndProcedure
 
  Macro WaitSemaphore(s)
    WaitSemaphore_proc(s)
  EndMacro
 
  Macro SignalSemaphore(s)
    SignalSemaphore_proc(s)
  EndMacro
CompilerEndIf
Nur so als Idee. Kann man ja auf Mutex umbauen.
semaphoreName() greift direkt auf die relevanten Variablen zu um den 'Namen' auszugeben, was in deinem Fall wahrscheinlich nicht so einfach ist, da du ja verschiedene pro Strukur/Element hast.

_________________
my pb stuff..
Bild..jedenfalls war das mal so.


Nach oben
 Profil  
Mit Zitat antworten  
 Betreff des Beitrags: Re: Mehrfaches Lock-/UnlockMutex im selben thread
BeitragVerfasst: 16.03.2019 13:34 
Offline
Benutzeravatar

Registriert: 24.11.2004 13:12
Wohnort: Germany
Ich weiss nicht ob das CanvasGadget ein StartDrawing aus einen Thread unter Linux oder MacOS mag...
Änderungen an Gadget aus Threads funktionieren nicht unter Linux oder MacOS.
Daher gibt es ja mein Modul ThreadToGUI

_________________
Alles ist möglich, fragt sich nur wie...
Projekte EventDesigner v1.x / OOP-BaseClass-Modul / OPC-Helper DLL
PB v3.30 / v5.4x - OS Mac Mini OSX 10.xx / Window 10 Pro. (X64) /Window 7 Pro. (X64) / Window XP Pro. (X86) / Ubuntu 14.04
Downloads auf Webspace


Nach oben
 Profil  
Mit Zitat antworten  
Beiträge der letzten Zeit anzeigen:  Sortiere nach  
Ein neues Thema erstellen Auf das Thema antworten  [ 19 Beiträge ]  Gehe zu Seite 1, 2  Nächste

Alle Zeiten sind UTC + 1 Stunde [ Sommerzeit ]


Wer ist online?

Mitglieder in diesem Forum: 0 Mitglieder und 3 Gäste


Sie dürfen keine neuen Themen in diesem Forum erstellen.
Sie dürfen keine Antworten zu Themen in diesem Forum erstellen.
Sie dürfen Ihre Beiträge in diesem Forum nicht ändern.
Sie dürfen Ihre Beiträge in diesem Forum nicht löschen.

Suche nach:
Gehe zu:  

 


Powered by phpBB © 2008 phpBB Group | Deutsche Übersetzung durch phpBB.de
subSilver+ theme by Canver Software, sponsor Sanal Modifiye