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:

Threadwait und ThreadCall

 
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
hhr



Anmeldungsdatum: 15.07.2020
Beiträge: 84

BeitragVerfasst am: 22.12.2021, 14:08    Titel: Threadwait und ThreadCall Antworten mit Zitat

In der Do-Schleife des Hauptprogramms stehen Zeilen mit Threadwait und ThreadCall,
die ich gern am Ende der Funktion get_i hätte. Das Programm funktioniert dann aber nicht.

Hat jemand einen Rat?
Code:
Dim Shared As Ulong i
Dim Shared As Boolean stop_counter,counter_stopped

Sub counter
   Do
      i+=1
   Loop Until stop_counter = True
   counter_stopped = True
End Sub

Function get_i As Ulong
   stop_counter = True
   Do
   Loop Until counter_stopped = True
   Function = i
   stop_counter = False
   counter_stopped = False
End Function

Dim As Any Ptr startcounter = ThreadCall counter

'===================================

Do
   Sleep 1,1
   Print get_i
   Threadwait startcounter
   startcounter = ThreadCall counter
Loop Until Len(Inkey)
'
Nach oben
Benutzer-Profile anzeigen Private Nachricht senden
nemored



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

BeitragVerfasst am: 22.12.2021, 18:28    Titel: Antworten mit Zitat

So?
Code:
Dim Shared As Ulong i
Dim Shared As Boolean stop_counter,counter_stopped

Sub counter
   Do
      i+=1
   Loop Until stop_counter = True
   counter_stopped = True
End Sub

Function get_i(Byref c As Any Ptr) As ULong
   stop_counter = True
   Do
   Loop Until counter_stopped = True
   get_i = i
   stop_counter = False
   counter_stopped = False
   Threadwait c
   c = ThreadCall counter
End Function

Dim As Any Ptr startcounter = ThreadCall counter

'===================================

Do
   Sleep 1,1
   Print get_i(startcounter)
Loop Until Len(Inkey)

Dass ich "get_i =" statt "Function =" geschrieben habe, liegt nur daran, dass ich den Syntax-Check meiner IDE nicht aus dem Tritt bringen wollte.

Ich muss aber dazu sagen, dass Threads nicht gerade zu meinen Stärken gehören. Meine Vorgehensweise scheint zu laufen - ob sie sinnvoll ist, kann ich schwer beurteilen.
_________________
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
ThePuppetMaster



Anmeldungsdatum: 18.02.2007
Beiträge: 1837
Wohnort: [JN58JR]

BeitragVerfasst am: 22.12.2021, 19:52    Titel: Re: Threadwait und ThreadCall Antworten mit Zitat

Hi hhr,

ansich ginge das schon, aber du hast ein paar Strukturelle Fehler drin, welche dir auch noch ungeahnte Probleme erzeugen >könnten< (Problem von Threads ansich).

Ich empfehle ... https://www.freebasic-portal.de/tutorials/mutexe-54.html ... sowie ... https://www.freebasic-portal.de/tutorials/threading-56.html


Code:
Dim Shared Counter_Count as UInteger
Dim Shared Counter_DoStop As Boolean
Dim Shared Counter_Stopped as Boolean
Dim Shared Counter_Mutex as Any Ptr

Sub Counter
'ALLE Variablen welche auch außerhalb eines Threads genutzt werden, müssen durch ein Mutex gesperrt werden.
MutexLock(Counter_Mutex)
Counter_Stopped = False
MutexUnLock(Counter_Mutex)
Do
    MutexLock(Counter_Mutex)
    Counter_Count += 1
    If Counter_DoStop = True Then
        MutexUnLock(Counter_Mutex)
        Exit Do
    End If
    MutexUnLock(Counter_Mutex)
Loop
MutexLock(Counter_Mutex)
Counter_Stopped = True
MutexUnLock(Counter_Mutex)
End Sub

Function get_i As Ulong
Do
    Sleep 1, 1 'Das Sleep sollte NICHT in ein MutexLock, sondern immer außerhalb genutzt werden.
    MutexLock(Counter_Mutex)
    If Counter_Count >= 10 Then 'Hier auf = UND > Prüfen!
        Counter_DoStop = True 'Dem Counter_Thread mitteilen, das er sich beenden soll.
        MutexUnLock(Counter_Mutex) 'Damit der Thread wieder weiter arbeiten kann, müssen wir das Mutex entsperren. Erst dann können wir die Blockierende ThreadWait Funktion aufrufen.
        ThreadWait(Counter_Thread)
        MutexLock(Counter_Mutex) 'Wenn der Thread beendet wurde, kommen wir aus der Wait Funktion heraus. Hier sollten wir das Mutex auch wieder sperren. -> 2x MutexUnLock ist nicht gut!! Lock -> UnLock -> Lock -> Unlock ... ist richtig.
    End If
    If Counter_Stopped = True Then
        MutexUnLock(Counter_Mutex)
        Exit Do
    End if
    MutexUnLock(Counter_Mutex)
Loop
Return Counter_Count
End Function


Counter_Mutex = MutexCreate()
Dim Counter_Thread As Any Ptr

Do
    'Die Reihenfolge ist hier entscheidend, weil du am ende der Schleife auf ein InKey wartest, der Thread aber noch läufen könnte (ThreadWait ist bei dir am anfang der do, und nicht am ende
    Counter_Thread = ThreadCreate(Counter)
    Print get_i
    Sleep 1, 1
Loop Until Len(Inkey)

MutexDestroy(Counter_Mutex) 'Alles was man erzeugt sollte man auch wieder entfernen
End 0 'Prog sauber beenden



MfG
TPM
_________________
[ WebFBC ][ OPS ][ ToOFlo ][ Wiemann.TV ]
Nach oben
Benutzer-Profile anzeigen Private Nachricht senden
hhr



Anmeldungsdatum: 15.07.2020
Beiträge: 84

BeitragVerfasst am: 23.12.2021, 15:03    Titel: Antworten mit Zitat

Danke für die Antworten.

Man muss also den Pointer übergeben.
Byref ist auch sehr wichtig, das habe ich nicht gewusst.
Wenn Byref fehlt, zeigt der Task-Manager an, dass die Anzahl der Handles
zunehmend größer wird und zunehmend Arbeitsspeicher gebraucht wird.
Das Programm funktioniert jetzt.

Dann habe ich mich um die zweite Antwort bemüht und versucht,
das in ein fertiges Programm umzusetzen.
Die Kritik war sehr hilfreich.

Darf ich noch um eine kritische Durchsicht des folgenden Programms bitten?
Ich habe nicht verstanden, wofür man (Byval Parameter As Any Ptr)
in der Sub Counter braucht. Das habe ich in der FB-Hilfe gelesen.

Gruß
hhr
Code:
Dim As Any Ptr Counter_Thread
Dim Shared As Any Ptr Counter_Mutex

Dim Shared As Boolean Counter_Stop
Dim Shared As Ulong Counter_Count
Dim Shared As Ulong sum

Sub Counter(Byval Parameter As Any Ptr)
   Do
      Mutexlock Counter_Mutex
      Counter_Count += 1
      If Counter_Stop = True Then
         Mutexunlock(Counter_Mutex)
         Exit Do
      End If
      Mutexunlock(Counter_Mutex)
   Loop
End Sub

Counter_Mutex = Mutexcreate
Counter_Thread = Threadcreate(@Counter)

Function parity32(Byval n As Ulong) As Ubyte
   n = n Xor (n Shr 16)
   n = n Xor (n Shr 8)
   n = n Xor (n Shr 4)
   n = n Xor (n Shr 2)
   n = n Xor (n Shr 1)
   Return n And 1
End Function

Function nextnumber As Ubyte
   Mutexlock Counter_Mutex
   sum += Counter_Count
   Mutexunlock Counter_Mutex
   Function = parity32(sum)
End Function

#Macro End_Program
   Mutexlock Counter_Mutex
   Counter_Stop = True
   Mutexunlock Counter_Mutex
   Threadwait Counter_Thread
   Mutexdestroy Counter_Mutex
   End
#Endmacro

'=================================================

Do
   Print nextnumber;
Loop Until Len(Inkey)

End_Program
Nach oben
Benutzer-Profile anzeigen Private Nachricht senden
ThePuppetMaster



Anmeldungsdatum: 18.02.2007
Beiträge: 1837
Wohnort: [JN58JR]

BeitragVerfasst am: 23.12.2021, 16:21    Titel: Antworten mit Zitat

Sieht top aus.


ByVal bedeutet, das man den Wert, welchen man an eine Funktion übergeben möchte, in einen eigenen Speicherbereich kopiert, der nur für die Funktion zur verfügung steht.

ByRef bedeutet, das man eine Variable hat, welche man einer Funktion zur verfügung stellt. Das bedeutet, das auch andere Programmteile auf diese Variable zugreifen könnten.

Da man ein Thread als eigenständig laufendes Programm betrachten kann, muss man hier beachten, das die variablen des Threads und deren Funktionen eigenständig laufen. Das bedeutet auch, das Variablen nach deren Erzeugung auch für den Thread weiter bestehen müssen.

Ein Beispiel:

Code:

sub Test(byref var as integer)
print var
end sub

sub bar()
dim foo as integer = 1
threadcall test(foo)
end sub

bar()
end 0


was passiert jetzt hier? ->
1. es wird die sub/Funktion "bar aufgerufen.
2. Die sub/funktion bar erzeugt eine variable welche nur in der funktion/sub zur verfügung steht
3. Die Funktion bar erzeugt einen Thread und übergibt dabei die variable foo. Dieser führt die sub Test aus.
4. Die Sub bar ist am ende, und deren variablen werden wieder entfernt.
5. Da der Zeitpunkt, ab dem der Thread läuft, nicht bekannt ist, könnte es passieren, das der Thread ausgeführt wird, bevor die sub bar entfernt wird, ODER erst NACHDEM die sub bar entfernt wurde. -> Großes Problem.

Es könnte jetz nämlich passieren, das der Thread auf die variable var der Funktion Test zugreifen möchte (Print var). Da diese Variable (var) allerdings eine REFERENZ ist, versucht der Print befehl auf die Variable foo zu zu greifen. Diese könnte allerdigns nicht mehr existieren, udn der Thread und das restliche prog stürzt ab. (Variable nicht mehr vorhanden -> die folge: MAE (Memory Access Error))

Daher nutzt man byval. Dies erzeugt eine Kopie der Daten in einer eigenen variable für diese Funktion Test. Dami ist es egal, ob die ausrufende Funktion/Sub noch existiert, oder nicht.


EDIT: Threads übergeben bei einem Aufruf einer Sub/Funktion eine Variable für mögliche Variablen-anlieferung. Und dies als Pointer auf eine im Thread laufenden Speicherbereich. Daher ist, um den Thread sauber starten zu können, immer eine Angabe einer Variable / eines Wertes nötig.


MfG
TPM
_________________
[ WebFBC ][ OPS ][ ToOFlo ][ Wiemann.TV ]
Nach oben
Benutzer-Profile anzeigen Private Nachricht senden
hhr



Anmeldungsdatum: 15.07.2020
Beiträge: 84

BeitragVerfasst am: 23.12.2021, 19:30    Titel: Antworten mit Zitat

Vor drei Tagen dachte ich noch, dass ich das nicht hinbekommen könnte.

Vielen Dank und frohe Weihnachten.

hhr
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