|
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 |
hhr
Anmeldungsdatum: 15.07.2020 Beiträge: 88
|
Verfasst am: 22.12.2021, 15:08 Titel: Threadwait und ThreadCall |
|
|
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 |
|
|
nemored
Anmeldungsdatum: 22.02.2007 Beiträge: 4597 Wohnort: ~/
|
Verfasst am: 22.12.2021, 19:28 Titel: |
|
|
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 |
|
|
ThePuppetMaster
Anmeldungsdatum: 18.02.2007 Beiträge: 1837 Wohnort: [JN58JR]
|
Verfasst am: 22.12.2021, 20:52 Titel: Re: Threadwait und ThreadCall |
|
|
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 |
|
|
hhr
Anmeldungsdatum: 15.07.2020 Beiträge: 88
|
Verfasst am: 23.12.2021, 16:03 Titel: |
|
|
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 |
|
|
ThePuppetMaster
Anmeldungsdatum: 18.02.2007 Beiträge: 1837 Wohnort: [JN58JR]
|
Verfasst am: 23.12.2021, 17:21 Titel: |
|
|
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 |
|
|
hhr
Anmeldungsdatum: 15.07.2020 Beiträge: 88
|
Verfasst am: 23.12.2021, 20:30 Titel: |
|
|
Vor drei Tagen dachte ich noch, dass ich das nicht hinbekommen könnte.
Vielen Dank und frohe Weihnachten.
hhr |
|
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.
|
|