|
Das deutsche QBasic- und FreeBASIC-Forum Für euch erreichbar unter qb-forum.de, fb-forum.de und freebasic-forum.de!
|
Vorheriges Thema anzeigen :: Nächstes Thema anzeigen |
Autor |
Nachricht |
Elor
Anmeldungsdatum: 12.07.2013 Beiträge: 205 Wohnort: Konstanz
|
Verfasst am: 19.10.2016, 12:18 Titel: Problem bei überschreiben einer OOP Methode |
|
|
Also, ich habe ein Objekt das zwei Threads erzeugt. Einer überwacht die ScreenEvents, der andere, falls erzeugt, den/die Joysticks. Beide Threads rufen bei einem eingetretenen Ereignis die Methode HandleEvents () auf. Das Funktioniert auch.
Wenn ich dieses Objekt nun weiter vererbe, in der ja dann die Methode HandleEvents () überschrieben wird, dann gibt es ein Segmentation fault (Linux), also das Programm startet erst gar nicht.
Hat jemand vielleicht eine Idee was da schief läuft? |
|
Nach oben |
|
|
St_W
Anmeldungsdatum: 22.07.2007 Beiträge: 949 Wohnort: Austria
|
Verfasst am: 19.10.2016, 17:26 Titel: |
|
|
Kannst du das Problem auf ein kleines Beispielprogramm reduzieren?
Compilierst du mit -exx?
Wo (im Code) tritt der SegFault auf?
Hast du schon tools wie Dr.Memory (Win+Lin) oder Valgrind (Lin) verwendet?
Denn möglicherweise hat der SegFault eine ganz andere Ursache und wird nur zufällig durch deine Codeänderung ersichtlich. _________________ Aktuelle FreeBasic Builds, Projekte, Code-Snippets unter http://users.freebasic-portal.de/stw/
http://www.mv-lacken.at Musikverein Lacken (MV Lacken) |
|
Nach oben |
|
|
Elor
Anmeldungsdatum: 12.07.2013 Beiträge: 205 Wohnort: Konstanz
|
Verfasst am: 20.10.2016, 10:32 Titel: |
|
|
Hier mal ein kleines Beispiel:
Code: |
#include "fbgfx.bi"
Type TEvent As FB.EVENT
Type _
THandleEvents Extends Object
Public :
Declare Constructor ()
Declare Sub Create ()
Declare Virtual Destructor
Protected :
Done As Boolean
Declare Sub ScreenEventThread ()
Declare Virtual Sub HandleEvent (ByVal Event As TEvent)
Private :
Mutex As Any Ptr
fbEvents As Any Ptr 'Thread
End Type
Type _
TApp Extends THandleEvents
Declare Sub HandleEvent (ByVal Event As TEvent) Override
End Type
Sub TApp.HandleEvent (ByVal Event As TEvent)
Base.HandleEvent (Event)
Select Case Event.Type
Case FB.EVENT_KEY_PRESS
Print ("Taste = "& Chr (Event.Ascii))
End Select
End Sub
Dim Test As TApp
ScreenRes (640, 480)
Test.Create ()
Constructor THandleEvents ()
Done= False
Mutex= MutexCreate ()
End Constructor
Sub THandleEvents.Create ()
fbEvents= ThreadCall ScreenEventThread ()
ThreadWait (fbEvents)
End Sub
Sub THandleEvents.ScreenEventThread ()
Dim As TEvent Event
Do
MutexLock (Mutex)
If ScreenEvent (@Event) Then
HandleEvent (Event)
End If
If Done Then Exit Do
MutexUnLock (Mutex)
Loop
MutexUnLock (Mutex)
End Sub
Sub THandleEvents.HandleEvent (ByVal Event As TEvent)
Select Case Event.Type
Case FB.EVENT_KEY_PRESS
If(Event.ScanCode = FB.SC_ESCAPE) Then Done= True
End Select
End Sub
Destructor THandleEvents ()
'ThreadWait (fbEvents) ' Das war der Fehler!
MutexDestroy (Mutex)
End Destructor
|
Gut, ist doch etwas länger, aber so kann man es wenigstens mal aus probieren.
Allerdings hab ich den Fehler gefunden, der saß wieder mal vor dem Bildschirm . Ich habe ThreadWait in den Destructor gesetzt und nicht in die Create-Methode
Vielen dank St_W für deine Bemühungen.
|
|
Nach oben |
|
|
Elor
Anmeldungsdatum: 12.07.2013 Beiträge: 205 Wohnort: Konstanz
|
Verfasst am: 22.10.2016, 11:27 Titel: |
|
|
Ich steh grad mal wieder mal ziemlich auf dem Schlauch, Ich mach folgendes...
Ich ermittle im Konstruktor die Anzahl der angeschlossenen Joysticks, wobei mit Aufruf der Sub Create (AnzahlJoysticks) die tatsächliche Anzahl zu verwendender Joysticks festgelegt wird (default = 0 = kein Joystick).
Wenn das Programm komplett initialisiert ist wird MainLoop () aufgerufen. Dort erzeuge ich den ScreenEventThread und dann, falls gewünscht, die entsprechende Anzahl Joystick Threads in einer For-Next-Schleife. Diese wird korrekt durchlaufen wobei die schleifen variable als Joystick Nummer an den Thread übergeben wird. Bei einem Joystick wird die schleife genau einmal durchlaufen und die Joystick Nummer 0 übergeben. Im Thread kommt dann aber eine 1 an!?
Falls nötig kann ich auch den ganzen Code Posten. |
|
Nach oben |
|
|
nemored
Anmeldungsdatum: 22.02.2007 Beiträge: 4601 Wohnort: ~/
|
Verfasst am: 22.10.2016, 15:21 Titel: |
|
|
So auf rein theoretischer Basis ist das etwas schwer zu analysieren. Wird denn die Laufvariable der Schleife während des Schleifendurchlaufs übergeben oder erst nach Abschluss? In letzterem Fall wäre klar, dass der Variablenwert 1 ist, ebenso wenn der Thread in der Schleife aufgerufen wird, sich aber bis zur Abarbeitung der Wert der Laufvariablen geändert hat. _________________ Deine Chance beträgt 1:1000. Also musst du folgendes tun: Vergiss die 1000 und konzentriere dich auf die 1. |
|
Nach oben |
|
|
Elor
Anmeldungsdatum: 12.07.2013 Beiträge: 205 Wohnort: Konstanz
|
Verfasst am: 22.10.2016, 17:30 Titel: |
|
|
nemored hat Folgendes geschrieben: | ...Wird denn die Laufvariable der Schleife während des Schleifendurchlaufs übergeben oder erst nach Abschluss? |
Der wert wird innerhalb der Schleife übergeben. Beispiel:
Code: |
Constructor TMyApp ()
'hier wird geprüft ob und wie viel Joysticks vorhanden sind
MaxJoystick= 0
For I As Integer= 0 To 15
If(GetJoystick (I) = 0) Then
MaxJoystick= MaxJoystick+ 1
Else
Exit For
End If
Next I
End Constructor
Sub TMyApp.Create (ByVal Joysticks As Integer)
Joysticks= JoySticks- 1
If(Joysticks > -1) Or (Joysticks < MaxJoystick) Then
ReDim PadThreads(Joysticks) ' vom type Any Ptr
End If
PadExist= True
End Sub
' und hier nun die SUB mainLoop ()
Sub TMyApp.MainLoop ()
' ScreenEventThread erzeugen
' ...
' und dann, falls vohanden, die Joysticks
If PadExist Then
For I As Integer= 0 To uBound (PadThreads)
PadThreads())= ThreadCall JoystickEventThread (I)
Next I
End If
UserProc () ' im event Objekt als abstrakt deklariert
' und hier die ThreadWaits
End Sub
|
Ich hab die Variable auch schon vor der Übergabe überprüft und die ist korrekt, deshalb versteh ich das nicht.
Wenn die Threads einzeln erzeugt werden Funktionierts, aber nur unter Linux. Unter Window 8.1/10 schaff ich es überhaupt nicht den Joystick mit einem im Objekt erzeugtem Thread aus zu lesen. |
|
Nach oben |
|
|
nemored
Anmeldungsdatum: 22.02.2007 Beiträge: 4601 Wohnort: ~/
|
Verfasst am: 22.10.2016, 20:15 Titel: |
|
|
Code: | ' Achtung, nicht threadsafe!
sub thread(i as integer)
print i
end sub
dim as integer nr = 1
dim as integer ptr thr = threadcall thread(nr)
nr = 7
threadwait(thr)
|
Da erhalte ich die Rückgabe 7, was mich nicht verwundert. Immerhin laufen die Threads ja parallel.
Deine Übergabe scheint mir übrigens genauso wenig threadsafe zu sein. _________________ Deine Chance beträgt 1:1000. Also musst du folgendes tun: Vergiss die 1000 und konzentriere dich auf die 1. |
|
Nach oben |
|
|
grindstone
Anmeldungsdatum: 03.10.2010 Beiträge: 1213 Wohnort: Ruhrpott
|
Verfasst am: 23.10.2016, 00:05 Titel: |
|
|
@Elor: Ich kann deine Beobachtung nicht bestätigen.
Code: | Type TMyApp
MaxJoystick As Integer
PadExist As boolean
ReDim As Any Ptr PadThreads(0)
Declare Constructor()
Declare Sub Create (ByVal Joysticks As Integer)
Declare Sub MainLoop ()
Declare Sub JoystickEventThread(parameter As Integer)
End Type
Dim As TMyApp test
test.mainloop()
Sleep
Constructor TMyApp ()
'hier wird geprüft ob und wie viel Joysticks vorhanden sind
MaxJoystick= 0
For I As Integer= 0 To 15
If(GetJoystick (I) = 0) Then
MaxJoystick= MaxJoystick+ 1
Else
Exit For
End If
Next I
? "Constructor: MaxJoystick ";MaxJoystick
End Constructor
Sub TMyApp.Create (ByVal Joysticks As Integer)
Joysticks= JoySticks- 1
? "Create: Joysticks ";Joysticks
If(Joysticks > -1) Or (Joysticks < MaxJoystick) Then
ReDim PadThreads(Joysticks) ' vom type Any Ptr
End If
PadExist= True
End Sub
' und hier nun die SUB mainLoop ()
Sub TMyApp.MainLoop ()
' ScreenEventThread erzeugen
' ...
' und dann, falls vohanden, die Joysticks
create(MaxJoystick)
? "MainLoop: PadExist ";PadExist
? "MainLoop: PadThreads ";uBound (PadThreads)
If PadExist Then
For I As Integer= 0 To uBound (PadThreads)
PadThreads(I)= ThreadCall JoystickEventThread (I)
Sleep 1
? "MainLoop: PadThreads(";I;") ";PadThreads(I)
Next I
End If
'UserProc () ' im event Objekt als abstrakt deklariert
' und hier die ThreadWaits
End Sub
Sub TMyApp.JoystickEventThread(parameter As Integer)
? "JoystickEventThread: parameter ";parameter
End Sub
| Der an JoystickEventThread übergebene Parameter ist 0 (WinXP).
Aber warum macht du die Sache so kompliziert? Die Sub Create kannst du dir komplett sparen, ebenso die Variable PadExist. Die Information, wieviele Joysticks angeschlossen sind (oder ob überhaupt einer), steckt auch in MaxJoystick; damit kannst du PadThreads schon im Constructor korrekt dimensionieren: Code: | Type TMyApp
MaxJoystick As Integer
ReDim As Any Ptr PadThreads(0)
Declare Constructor()
Declare Sub MainLoop ()
Declare Sub JoystickEventThread(parameter As Integer)
End Type
Dim As TMyApp test
test.mainloop()
Sleep
Constructor TMyApp ()
'hier wird geprüft ob und wie viel Joysticks vorhanden sind
MaxJoystick= 0
For I As Integer= 0 To 15
If(GetJoystick (I) = 0) Then
MaxJoystick= MaxJoystick+ 1
Else
Exit For
End If
Next I
? "Constructor: MaxJoystick ";MaxJoystick
ReDim PadThreads(MaxJoystick - 1)
End Constructor
' und hier nun die SUB mainLoop ()
Sub TMyApp.MainLoop ()
' ScreenEventThread erzeugen
' ...
' und dann, falls vohanden, die Joysticks
? "MainLoop: PadThreads ";uBound (PadThreads)
If MaxJoystick Then
For I As Integer= 0 To uBound (PadThreads)
PadThreads(I)= ThreadCall JoystickEventThread (I)
Sleep 1
? "MainLoop: PadThreads(";I;") ";PadThreads(I)
Next I
End If
'UserProc () ' im event Objekt als abstrakt deklariert
' und hier die ThreadWaits
End Sub
Sub TMyApp.JoystickEventThread(parameter As Integer)
? "JoystickEventThread: parameter ";parameter
End Sub
|
nemored hat übrigens recht: Die Übergabe ist nicht threadsafe. Das siehst du, wenn du das "Sleep 1" auskommentierst.
Gruß
grindstone _________________ For ein halbes Jahr wuste ich nich mahl wie man Proggramira schreibt. Jetzt bin ich einen! |
|
Nach oben |
|
|
Elor
Anmeldungsdatum: 12.07.2013 Beiträge: 205 Wohnort: Konstanz
|
Verfasst am: 23.10.2016, 11:23 Titel: |
|
|
nemored hat Folgendes geschrieben: | Code: | ' Achtung, nicht threadsafe!
sub thread(i as integer)
print i
end sub
dim as integer nr = 1
dim as integer ptr thr = threadcall thread(nr)
nr = 7
threadwait(thr)
|
Da erhalte ich die Rückgabe 7, was mich nicht verwundert. Immerhin laufen die Threads ja parallel.
Deine Übergabe scheint mir übrigens genauso wenig threadsafe zu sein. |
Ich weiß jetzt nicht genau auf was sich das threadsafe bezieht, aber dein kleines Beispiel hat mich doch auf eine Lösung gebracht. Ich habe nach dem erzeugen des threads eine kleine Pause eingelegt, jetzt Funktionierts. Ich hab dann gesehen, dass es grindstone genauso gemacht hat, allerdings reicht bei mir eine Millisekunde nicht, ich hab mal sicherheitshalber 5 eingesetzt.
grindstone hat Folgendes geschrieben: | @Elor: Ich kann deine Beobachtung nicht bestätigen. |
Meine Beobachtung bezog sich auf Windows10(32) und Windows 8.1(64). Außerhalb eines Objekts Funktionierts, innerhalb (noch) nicht.
Zitat: | Aber warum macht du die Sache so kompliziert? Die Sub Create kannst du dir komplett sparen, ebenso die Variable PadExist. Die Information, wieviele Joysticks angeschlossen sind (oder ob überhaupt einer), steckt auch in MaxJoystick; damit kannst du PadThreads schon im Constructor korrekt dimensionieren: |
Die Variable PadExists kann ich mir tatsächlich sparen, da hast du recht. Mit der Methode Create sieht es anders aus. Mich stört es ein wenig das die Konstruktoren Automatisch aufgerufen werden, haben diese auch noch Parameter, kommt der Compiler ständig mit seinen fehlenden default Konstruktoren. Deshalb verwende ich in allen Objekten eine Create Methode mit der ich selber entscheiden kann wann und wie ich etwas initialisieren will. In diesem Fall möchte ich das man angeben kann wie viele Joysticks verwendet werden sollen, egal wie viele angeschlossen sind. Es gibt ja auch Anwendungen die keinen Joystick benötigen.
Jetzt probier ich das ganze nochmal auf Windows und Melde mich dann wieder mit dem Ergebnis. |
|
Nach oben |
|
|
nemored
Anmeldungsdatum: 22.02.2007 Beiträge: 4601 Wohnort: ~/
|
Verfasst am: 23.10.2016, 13:06 Titel: |
|
|
"nicht threadsafe" bedeutet genau dieses, dass das Hauptprogramm den Variablenwert ändern kann, während er vom Thread bearbeitet wird. Im schlechtesten Fall (und wenn das Programm komplex genug ist und lang genug läuft, wird das früher oder später passieren) hast du einen Zugriff genau zur gleichen Zeit, und das Programm hängt sich auf. Obwohl, vielleicht ist das gar nicht der schlechteste Fall, denn dann merkt man wenigstens, dass was hakt ...
Eine künstliche Pause einzufügen mag in diesem Augenblick genügen, löst aber das Problem nicht, sondern verschleiert es nur. Wenn in irgendeiner anderen Systemkonfiguration das Starten des Threads länger als 5 ms dauert, hast du dasselbe Problem wieder. Sinnvoller wäre es vermutlich, in irgendeiner Form sicherzustellen, dass der Thread korrekt gestartet ist. _________________ Deine Chance beträgt 1:1000. Also musst du folgendes tun: Vergiss die 1000 und konzentriere dich auf die 1. |
|
Nach oben |
|
|
grindstone
Anmeldungsdatum: 03.10.2010 Beiträge: 1213 Wohnort: Ruhrpott
|
Verfasst am: 23.10.2016, 13:45 Titel: |
|
|
Stimmt, das "Sleep" war auch nur ein Behelf, um das Problem zu verdeutlichen. Eine saubere Lösung ist ein klein wenig komplizierter: Code: | Dim Shared As Any Ptr mu
Dim Shared As Integer threadMessage
mu = MutexCreate
Type TMyApp
MaxJoystick As Integer
PadExist As boolean
ReDim As Any Ptr PadThreads(0)
Declare Constructor()
Declare Sub Create (ByVal Joysticks As Integer)
Declare Sub MainLoop ()
Declare Sub JoystickEventThread(parameter As Integer)
End Type
Dim As TMyApp test
test.mainloop()
MutexDestroy mu
? "Programm beendet"
Sleep
Constructor TMyApp ()
'hier wird geprüft ob und wie viel Joysticks vorhanden sind
MaxJoystick= 0
For I As Integer= 0 To 15
If(GetJoystick (I) = 0) Then
MaxJoystick= MaxJoystick+ 1
Else
Exit For
End If
Next I
? "Constructor: MaxJoystick ";MaxJoystick
End Constructor
Sub TMyApp.Create (ByVal Joysticks As Integer)
Joysticks= JoySticks- 1
? "Create: Joysticks ";Joysticks
If(Joysticks > -1) Or (Joysticks < MaxJoystick) Then
ReDim PadThreads(Joysticks) ' vom type Any Ptr
End If
PadExist= True
End Sub
' und hier nun die SUB mainLoop ()
Sub TMyApp.MainLoop ()
' ScreenEventThread erzeugen
' ...
' und dann, falls vohanden, die Joysticks
create(MaxJoystick)
? "MainLoop: PadExist ";PadExist
? "MainLoop: PadThreads ";uBound (PadThreads)
If PadExist Then
For I As Integer= 0 To uBound (PadThreads)
PadThreads(I)= ThreadCall JoystickEventThread (I)
Do
MutexLock mu
If threadMessage = 1 Then 'thread gestartet
threadMessage = 0
MutexUnLock mu
Exit Do
EndIf
MutexUnLock mu
Loop
MutexLock mu
? "MainLoop: PadThreads(";I;") ";PadThreads(I)
MutexUnLock mu
Next I
End If
Do
MutexLock mu
Locate 10,1
? Timer
MutexUnLock mu
Sleep 1
Loop While InKey = ""
MutexLock mu
threadMessage = 2
MutexUnLock mu
For I As Integer= 0 To uBound (PadThreads)
ThreadWait PadThreads(I)
? "Thread ";I;" beendet"
Next
'UserProc () ' im event Objekt als abstrakt deklariert
' und hier die ThreadWaits
End Sub
Sub TMyApp.JoystickEventThread(parameter As Integer)
Dim As Integer buttons, ende
Dim As Single x, y
? "JoystickEventThread: parameter ";parameter
'Sleep 100
MutexLock mu
threadMessage = 1
MutexUnLock mu
Do
GetJoystick(parameter, buttons, x, y)
MutexLock mu
Locate parameter + 15,1
? parameter, buttons, x, y
If threadMessage = 2 Then
ende = 1
EndIf
MutexUnLock mu
Sleep 1
Loop Until ende
End Sub
| Insbesondere ist darauf zu achten, daß der Mutex nach dem Speicherzugriff wieder freigegeben wird. Ein vergessenes MutexUnLock kann für tagelange Beschäftigung sorgen.
Gruß
grindstone _________________ For ein halbes Jahr wuste ich nich mahl wie man Proggramira schreibt. Jetzt bin ich einen! |
|
Nach oben |
|
|
Elor
Anmeldungsdatum: 12.07.2013 Beiträge: 205 Wohnort: Konstanz
|
Verfasst am: 24.10.2016, 15:26 Titel: |
|
|
nemored hat Folgendes geschrieben: | "nicht threadsafe" bedeutet genau dieses, dass das Hauptprogramm den Variablenwert ändern kann, während er vom Thread bearbeitet wird. Im schlechtesten Fall (und wenn das Programm komplex genug ist und lang genug läuft, wird das früher oder später passieren) hast du einen Zugriff genau zur gleichen Zeit, und das Programm hängt sich auf. Obwohl, vielleicht ist das gar nicht der schlechteste Fall, denn dann merkt man wenigstens, dass was hakt ... |
Insofern habe ich threadsafe nicht ganz verstanden. Ich dachte immer das sich das auf SUB/FUNKTION und Datentypen bezieht die innerhalb des Threads verwendet werden.
Das mit dem Sleep war einfach so ein spontaner Einfall, aber stimmt schon, wirklich sauber ist das nicht.
Ich hab jetzt mal die Lösung von grindstone verwendet, Funktioniert, zumindest unter Linux (Windows muss ich noch testen).
Trotzdem noch eine frage an euch...
Das Hauptprogramm und die threads werden ja über die Variable Done (Boolean) Terminiert.
Da jeder darauf zugreift, muss diese Variable ja geschützt werden. Damit andere darauf zugreifen können, hab ich Properties zur Verfügung gestellt. In HandleEvents (...) frage ich dann die ESCAPE-Taste und das EVENT_WINDOW_COSE Ereignis ab und setze die Variable Done über die Propertie ExitCmd auf True. Die Threads werden zwar beendet, dass Programm aber nicht. Erst wenn ich direkt ohne Mutexlock () auf die Variable Done zugreife Funktionierts. Warum ist mir aber nicht ganz klar. Falls gewünscht, Post ich mal alles was ich bis jetzt hab. |
|
Nach oben |
|
|
nemored
Anmeldungsdatum: 22.02.2007 Beiträge: 4601 Wohnort: ~/
|
Verfasst am: 24.10.2016, 16:09 Titel: |
|
|
Ich bin absolut kein Multithreading-Experte und kann dir leider auch nicht sagen, wie es richtig geht. Ich weiß nur ein paar Sachen, die man nicht machen sollte.
Threadsafe bezieht sich immer auf Threads, und das Hauptprogramm ist ebenfalls einer. Wenn du eine Variable ausschließlich im Hauptprogramm oder ausschließlich in einer SUB verwendest, passiert da natürlich auch nichts schlimmes. Die Variable(n), die mit THREADCALL übergeben wird/werden, sind aber mindestens ein Grenzfall. Wenn sie BYREF sind, entspricht das einer Nutzung in beiden Threads, womit ein Mutex-Schutz dringend erforderlich ist. Ist die Übergabe BYVAL, dann sollte ein Zugriff an sich threadsafe sein, aber solange der Thread noch nicht am Laufen ist (also solange die Parameterübergabe noch vorbereitet wird), ist da noch nichts sicher. Wie gesagt, du bist an dieser Stelle schon im Multithreading, und das Hauptprogramm wartet nicht darauf, dass der Aufruf erfolgreich durchgeführt wurde. Zumindest interpretiere ich die Ergebnisse in dieser Richtung. _________________ Deine Chance beträgt 1:1000. Also musst du folgendes tun: Vergiss die 1000 und konzentriere dich auf die 1. |
|
Nach oben |
|
|
grindstone
Anmeldungsdatum: 03.10.2010 Beiträge: 1213 Wohnort: Ruhrpott
|
Verfasst am: 24.10.2016, 16:40 Titel: |
|
|
Die Threadsicherheit bezieht sich auf die Speicherzugriffe, denn der Speicher ist ja für alle Prozessorkerne derselbe. Wenn die zugeteilte Rechenzeit vorbei ist, übergibt das Betriebssystem den Prozessorkern gnadenlos an den nächsten Thread. Greift nun einer oder mehrere der anderen Threads auf dieselbe Speicherstelle zu, ist deren Inhalt bei der nächsten Zeitscheibe möglicherweise geändert worden, ohne daß der Thread etwas davon mitbekommt.
Ein Mutex ist inetwa vergleichbar mit dem "Besetzt"-Zeichen an der Toilettentür. Wenn ein Thread auf einen verriegelten Mutex trifft, wird er beendet (ähnlich wie bei "Sleep") und der Zugriff auf den Prozessorkern an den nächsten Thread übergeben.
Die Gefahr, daß man unbeabsichtigt einen verriegelten Mutex zurücklässt, der dann das ganze Programm blockiert, besteht besonders beim Herausspringen aus Schleifen (z.B. Exit Do) und beim Beenden von Prozeduren (If xy Then Return).
Gruß
grindstone
EDIT: Upps, da war nemored (mal wieder) schneller. Aber ich denke, unsere Erklärungen ergänzen sich. _________________ For ein halbes Jahr wuste ich nich mahl wie man Proggramira schreibt. Jetzt bin ich einen! |
|
Nach oben |
|
|
Elor
Anmeldungsdatum: 12.07.2013 Beiträge: 205 Wohnort: Konstanz
|
Verfasst am: 24.10.2016, 17:25 Titel: |
|
|
Was mit der Thread Sicherheit gemeint ist hab ich jetzt (hoffentlich) verstanden. Hoffentlich deshalb, weil ja immer noch die oben erwähnte Done Variable existiert. In den Threads mach ich ja folgendes:
Code: |
Sub MyThread ()
Do
MutexLock (Mutex)
' hier frag ich ein Ereignis ab und rufe ggf. den Eventhandler auf
' und prüfe jetzt die Variable Done
If Done Then Exit Do
MutexUnlock (Mutex)
Loop
MutexUnlock (Mutex)
End Sub
|
Da kann ja kein MutexLock zurück bleiben.
In den Properties greif ich so drauf zu:
Code: |
Private Property TDrivers.ExitCmd As Boolean ' read Done
MutexLock (Mutex)
Property= Done
MutexUnLock (Mutex)
End Property
Private Property TDrivers.ExitCmd (ByVal Cmd As Boolean) ' write Done
MutexLock (Mutex)
Done= Cmd
MutexUnLock (Mutex)
End Property
|
Aber mit diesem Schutz funktionierts nicht, sondern nur ohne. Und deshalb hier immer noch die ??? |
|
Nach oben |
|
|
grindstone
Anmeldungsdatum: 03.10.2010 Beiträge: 1213 Wohnort: Ruhrpott
|
Verfasst am: 24.10.2016, 17:34 Titel: |
|
|
Du liest/schreibst die Variable Done doch sicher noch an anderen Stellen im Programm. Was ist damit?
Gruß
grindstone
EDIT:
Elor hat Folgendes geschrieben: | Code: | Sub MyThread ()
Do
MutexLock (Mutex)
' hier frag ich ein Ereignis ab und rufe ggf. den Eventhandler auf
' und prüfe jetzt die Variable Done
If Done Then Exit Do
MutexUnlock (Mutex)
Loop
MutexUnlock (Mutex)
End Sub |
| Rufst du vielleicht innerhalb der Do - Schleife eine der Properties auf? Dann hängt sich das Programm selbstverständlich auf, da das MutexLock in der Property auf den verriegelten Mutex aus der Sub trifft.
Versuche es vielleicht mal so: Code: | Sub MyThread ()
Do
' hier frag ich ein Ereignis ab und rufe ggf. den Eventhandler auf
' und prüfe jetzt die Variable Done
MutexLock (Mutex)
If Done Then Exit Do
MutexUnlock (Mutex)
Loop
MutexUnlock (Mutex)
End Sub |
_________________ For ein halbes Jahr wuste ich nich mahl wie man Proggramira schreibt. Jetzt bin ich einen! |
|
Nach oben |
|
|
Elor
Anmeldungsdatum: 12.07.2013 Beiträge: 205 Wohnort: Konstanz
|
Verfasst am: 24.10.2016, 20:36 Titel: |
|
|
grindstone hat Folgendes geschrieben: | Du liest/schreibst die Variable Done doch sicher noch an anderen Stellen im Programm. Was ist damit? |
Es sind nur die Threads die direkt auf die Variable zugreifen (geschützt), alle anderen haben nur über die Properties zugriff. Ich hab das Ding schon was weiß ich wie oft nach Lock's durch sucht die man vielleicht übersehen hat, aber da ist nix. Das Property (geschützt) lesen funktioniert, aber das schreiben nicht. Ich glaube es ist doch besser wenn ich mal den sourcecode hier rein stell, vielleicht sieht dann jemand was, was ich nicht sehe.
Code: |
/' Include: fbEvents.bi '/
#pragma Once
#include "fbgfx.bi"
Const cmdGamePad = 4096
Type PMutex As Any Ptr
Type PThread As Any Ptr
Type _
TEvent Extends FB.EVENT
PadNum As Integer
JButton As Integer
As Single JX, JY, JZ, R, U, V
End Type
Type _
TDrivers Extends Object
Public :
Declare Constructor ()
Declare Sub MainLoop ()
Declare Property ExitCmd As Boolean ' read Done
Declare Property ExitCmd (ByVal Cmd As Boolean) ' write Done
Declare Virtual Destructor ()
Protected :
Done As Boolean
Declare Abstract Sub UserProc ()
Declare Sub ScreenEventThread ()
Declare Sub JoystickEventThread (ByVal PadNum As Integer)
Declare Virtual Sub HandleEvents (ByVal Event As TEvent)
Private :
Mutex As PMutex
kbThread As PThread
MaxPad As Integer
threadMessage As Integer
PadThreads(Any) As PThread
End Type
/' --- PUBLIC --- '/
Private Constructor TDrivers ()
Done= False
Mutex= MutexCreate ()
MaxPad= 0
For I As Integer= 0 To 15
If(GetJoystick (I) = 0) Then
MaxPad+= 1
End If
Next I
If(MaxPad > 0) Then
ReDim PadThreads(MaxPad- 1)
End If
End Constructor
Private Sub TDrivers.MainLoop ()
kbThread= ThreadCall ScreenEventThread ()
If(MaxPad > 0) Then
For I As Integer= 0 To MaxPad- 1
PadThreads(I)= ThreadCall JoystickEventThread (I)
Do
MutexLock (Mutex)
If(threadMessage = 1) Then
threadMessage= 0
Exit Do
End If
MutexUnlock (Mutex)
Loop
MutexUnlock (Mutex)
Next I
End If
UserProc ()
ThreadWait (kbThread)
If(MaxPad > 0) Then
For I As Integer= 0 To MaxPad- 1
ThreadWait (PadThreads(I))
Next I
End If
End Sub
Private Property TDrivers.ExitCmd As Boolean ' read Done
MutexLock (Mutex)
Property= Done
MutexUnLock (Mutex)
End Property
Private Property TDrivers.ExitCmd (ByVal Cmd As Boolean) ' write Done
'MutexLock (Mutex)
Done= Cmd
'MutexUnLock (Mutex)
End Property
Private Destructor TDrivers ()
MutexDestroy (Mutex)
End Destructor
/' --- PROTECTED --- '/
Private Sub TDrivers.ScreenEventThread ()
Dim Event As TEvent
Do
MutexLock (Mutex)
If ScreenEvent (@Event) Then
HandleEvents (Event)
End If
If Done Then Exit Do
MutexUnLock (Mutex)
Sleep (20)
Loop
MutexUnLock (Mutex)
End Sub
Private Sub TDRivers.JoystickEventThread (ByVal PadNum As Integer)
Dim Event As TEvent
MutexLock (Mutex)
threadMessage= 1
MutexUnlock (Mutex)
Do
MutexLock (Mutex)
With Event
GetJoystick (PadNum, .JButton, .JX, .JY, .JZ, .R, .U, .V)
If(.JButton <> 0) Or (.JX <> 0) Or (.JY <> 0) Or (.JZ <> 0) Or _
(.R <> 0) Or (.U <> 0) Or (.V <> 0) Then
Event.Type= cmdGamePad
Event.PadNum= PadNum
HandleEvents (Event)
End If
End With
If Done Then Exit Do
MutexUnlock (Mutex)
Sleep (20)
Loop
MutexUnlock (Mutex)
End Sub
Private Sub TDrivers.HandleEvents (ByVal Event As TEvent)
Select Case Event.Type
Case FB.EVENT_KEY_PRESS
If(Event.ScanCode = FB.SC_ESCAPE) Then
ExitCmd= True
End If
Case FB.EVENT_WINDOW_CLOSE
ExitCmd= True
End Select
End Sub
|
Und der teil zum testen:
Code: |
#include "fbgfx.bi"
Type _
TApp Extends TDrivers
Public :
Declare Constructor ()
Declare Sub UserProc () Override
Declare Sub HandleEvents (ByVal Event As TEvent) Override
End Type
Dim App As TApp
App.MainLoop ()
Constructor TApp ()
ScreenRes (640, 480)
Width 80, 30
End Constructor
Sub TApp.UserProc ()
Do
Print ("blablabla");
Sleep (100)
Loop Until ExitCmd
End Sub
Sub TApp.HandleEvents (ByVal Event As TEvent)
Base.HandleEvents (Event)
If(Event.Type = cmdGamePad) Then
Print "Joystick nummer "& Event.PadNum & " wurde gedrueckt!"
End If
End Sub
|
Ich hab hier im Forum schon längere Codes gesehen
Edit: Im Testprogramm fehlt hier noch #include "fbEvents.bi"! |
|
Nach oben |
|
|
nemored
Anmeldungsdatum: 22.02.2007 Beiträge: 4601 Wohnort: ~/
|
Verfasst am: 24.10.2016, 21:07 Titel: |
|
|
Versuche doch mal, in der SUB MyThread() hinter der Schleife nach dem MutexUnlock ein SLEEP 1 einzufügen - nicht wegen der Wartezeit, sondern damit der eine Thread kurz die Kontrolle an das System zurückgibt und der andere Thread aufgerufen werden kann. Zu diesem SLEEP 1 habe ich einerseits gelesen, dass es zur Kontroll-Abgabe unbedingt nötig ist, andererseits, dass es nicht threadsafe sei ... vielleicht ist letzte Information auch schon veraltet, ansonsten müsste man es wohl mit einem anderen Mutex schützen als den für die Variable Done. _________________ Deine Chance beträgt 1:1000. Also musst du folgendes tun: Vergiss die 1000 und konzentriere dich auf die 1. |
|
Nach oben |
|
|
Elor
Anmeldungsdatum: 12.07.2013 Beiträge: 205 Wohnort: Konstanz
|
Verfasst am: 25.10.2016, 10:38 Titel: |
|
|
Das mit dem Sleep funktioniert nicht, aber das getrennte schützen war die Lösung! Erst mal vielen dank für eure Hilfe. |
|
Nach oben |
|
|
nemored
Anmeldungsdatum: 22.02.2007 Beiträge: 4601 Wohnort: ~/
|
Verfasst am: 25.10.2016, 15:01 Titel: |
|
|
Ja richtig, jetzt mit ein bisschen Zeit und Muße sehe ich es: du sperrst in oberem Code den Zugriff auf HandleEvents mit einem Mutex, und innerhalb dieser Funktion rufst du dann ExitCmd auf, was wiederum denselben Mutex zu sperren versucht. _________________ Deine Chance beträgt 1:1000. Also musst du folgendes tun: Vergiss die 1000 und konzentriere dich auf die 1. |
|
Nach oben |
|
|
|
|
Du kannst keine Beiträge in dieses Forum schreiben. Du kannst auf Beiträge in diesem Forum nicht antworten. Du kannst deine Beiträge in diesem Forum nicht bearbeiten. Du kannst deine Beiträge in diesem Forum nicht löschen. Du kannst an Umfragen in diesem Forum nicht mitmachen.
|
|