Das deutsche QBasic- und FreeBASIC-Forum Foren-Übersicht Das deutsche QBasic- und FreeBASIC-Forum
Für euch erreichbar unter qb-forum.de, fb-forum.de und freebasic-forum.de!
 
FAQFAQ   SuchenSuchen   MitgliederlisteMitgliederliste   BenutzergruppenBenutzergruppen  RegistrierenRegistrieren
ProfilProfil   Einloggen, um private Nachrichten zu lesenEinloggen, um private Nachrichten zu lesen   LoginLogin
Zur Begleitseite des Forums / Chat / Impressum
Aktueller Forenpartner:

Problem bei überschreiben einer OOP Methode

 
Neues Thema eröffnen   Neue Antwort erstellen    Das deutsche QBasic- und FreeBASIC-Forum Foren-Übersicht -> Allgemeine Fragen zu FreeBASIC.
Vorheriges Thema anzeigen :: Nächstes Thema anzeigen  
Autor Nachricht
Elor



Anmeldungsdatum: 12.07.2013
Beiträge: 205
Wohnort: Konstanz

BeitragVerfasst am: 19.10.2016, 11:18    Titel: Problem bei überschreiben einer OOP Methode Antworten mit Zitat

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
Benutzer-Profile anzeigen Private Nachricht senden
St_W



Anmeldungsdatum: 22.07.2007
Beiträge: 949
Wohnort: Austria

BeitragVerfasst am: 19.10.2016, 16:26    Titel: Antworten mit Zitat

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
Benutzer-Profile anzeigen Private Nachricht senden
Elor



Anmeldungsdatum: 12.07.2013
Beiträge: 205
Wohnort: Konstanz

BeitragVerfasst am: 20.10.2016, 09:32    Titel: Antworten mit Zitat

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 grinsen . Ich habe ThreadWait in den Destructor gesetzt und nicht in die Create-Methode Kopf schütteln
Vielen dank St_W für deine Bemühungen.
Nach oben
Benutzer-Profile anzeigen Private Nachricht senden
Elor



Anmeldungsdatum: 12.07.2013
Beiträge: 205
Wohnort: Konstanz

BeitragVerfasst am: 22.10.2016, 10:27    Titel: Antworten mit Zitat

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
Benutzer-Profile anzeigen Private Nachricht senden
nemored



Anmeldungsdatum: 22.02.2007
Beiträge: 4594
Wohnort: ~/

BeitragVerfasst am: 22.10.2016, 14:21    Titel: Antworten mit Zitat

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
Benutzer-Profile anzeigen Private Nachricht senden
Elor



Anmeldungsdatum: 12.07.2013
Beiträge: 205
Wohnort: Konstanz

BeitragVerfasst am: 22.10.2016, 16:30    Titel: Antworten mit Zitat

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. verwundert
Nach oben
Benutzer-Profile anzeigen Private Nachricht senden
nemored



Anmeldungsdatum: 22.02.2007
Beiträge: 4594
Wohnort: ~/

BeitragVerfasst am: 22.10.2016, 19:15    Titel: Antworten mit Zitat

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
Benutzer-Profile anzeigen Private Nachricht senden
grindstone



Anmeldungsdatum: 03.10.2010
Beiträge: 1208
Wohnort: Ruhrpott

BeitragVerfasst am: 22.10.2016, 23:05    Titel: Antworten mit Zitat

@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
Benutzer-Profile anzeigen Private Nachricht senden E-Mail senden
Elor



Anmeldungsdatum: 12.07.2013
Beiträge: 205
Wohnort: Konstanz

BeitragVerfasst am: 23.10.2016, 10:23    Titel: Antworten mit Zitat

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. happy 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
Benutzer-Profile anzeigen Private Nachricht senden
nemored



Anmeldungsdatum: 22.02.2007
Beiträge: 4594
Wohnort: ~/

BeitragVerfasst am: 23.10.2016, 12:06    Titel: Antworten mit Zitat

"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
Benutzer-Profile anzeigen Private Nachricht senden
grindstone



Anmeldungsdatum: 03.10.2010
Beiträge: 1208
Wohnort: Ruhrpott

BeitragVerfasst am: 23.10.2016, 12:45    Titel: Antworten mit Zitat

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
Benutzer-Profile anzeigen Private Nachricht senden E-Mail senden
Elor



Anmeldungsdatum: 12.07.2013
Beiträge: 205
Wohnort: Konstanz

BeitragVerfasst am: 24.10.2016, 14:26    Titel: Antworten mit Zitat

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
Benutzer-Profile anzeigen Private Nachricht senden
nemored



Anmeldungsdatum: 22.02.2007
Beiträge: 4594
Wohnort: ~/

BeitragVerfasst am: 24.10.2016, 15:09    Titel: Antworten mit Zitat

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

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
Benutzer-Profile anzeigen Private Nachricht senden
grindstone



Anmeldungsdatum: 03.10.2010
Beiträge: 1208
Wohnort: Ruhrpott

BeitragVerfasst am: 24.10.2016, 15:40    Titel: Antworten mit Zitat

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. grinsen Aber ich denke, unsere Erklärungen ergänzen sich. lächeln
_________________
For ein halbes Jahr wuste ich nich mahl wie man Proggramira schreibt. Jetzt bin ich einen!
Nach oben
Benutzer-Profile anzeigen Private Nachricht senden E-Mail senden
Elor



Anmeldungsdatum: 12.07.2013
Beiträge: 205
Wohnort: Konstanz

BeitragVerfasst am: 24.10.2016, 16:25    Titel: Antworten mit Zitat

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
Benutzer-Profile anzeigen Private Nachricht senden
grindstone



Anmeldungsdatum: 03.10.2010
Beiträge: 1208
Wohnort: Ruhrpott

BeitragVerfasst am: 24.10.2016, 16:34    Titel: Antworten mit Zitat

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
Benutzer-Profile anzeigen Private Nachricht senden E-Mail senden
Elor



Anmeldungsdatum: 12.07.2013
Beiträge: 205
Wohnort: Konstanz

BeitragVerfasst am: 24.10.2016, 19:36    Titel: Antworten mit Zitat

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 lächeln

Edit: Im Testprogramm fehlt hier noch #include "fbEvents.bi"!
Nach oben
Benutzer-Profile anzeigen Private Nachricht senden
nemored



Anmeldungsdatum: 22.02.2007
Beiträge: 4594
Wohnort: ~/

BeitragVerfasst am: 24.10.2016, 20:07    Titel: Antworten mit Zitat

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
Benutzer-Profile anzeigen Private Nachricht senden
Elor



Anmeldungsdatum: 12.07.2013
Beiträge: 205
Wohnort: Konstanz

BeitragVerfasst am: 25.10.2016, 09:38    Titel: Antworten mit Zitat

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
Benutzer-Profile anzeigen Private Nachricht senden
nemored



Anmeldungsdatum: 22.02.2007
Beiträge: 4594
Wohnort: ~/

BeitragVerfasst am: 25.10.2016, 14:01    Titel: Antworten mit Zitat

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
Benutzer-Profile anzeigen Private Nachricht senden
Beiträge der letzten Zeit anzeigen:   
Neues Thema eröffnen   Neue Antwort erstellen    Das deutsche QBasic- und FreeBASIC-Forum Foren-Übersicht -> Allgemeine Fragen zu FreeBASIC. Alle Zeiten sind GMT + 1 Stunde
Seite 1 von 1

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

 Impressum :: Datenschutz