Seite 1 von 1
KillThread
Verfasst: 04.03.2012 17:43
von Daffy0815
Hallo Leute,
in der Dokumentation habe ich gelesen, das man möglichst von der Verwendung der KillThread-Anweisung absehen soll.
Ich habe einen Thread mit jeder Menge nacheinander angeordneten IF-ENDIF / verschachtelten While-Wend.
Wird der Thread komplett durchlaufen so ist er auch beendet.
Jetzt gibt es im Hauptprogramm einen Button mit dem man den Thread jederzeit beenden kann.
Die einfachste Lösung dafür wäre "KillThread" als Reaktion auf die Betätigung des Buttons.
Nach meinem Kentnisstand wäre die einzige "KillThread-freie-Lösung" eine Globalvariable die an zig Stellen innerhalb des Threads abgefragt werden müsste um diesen Thread zu beenden.
Gibt es da auch eine einfachere Lösung?
Gruß
Daffy
Re: KillThread
Verfasst: 04.03.2012 18:08
von ts-soft
Hier ein Beispiel ohne Globale Variable!
Es wird eine Semaphore als Signal verwendet.
Hier noch ein verkürztes Beispiel:
Code: Alles auswählen
EnableExplicit
Procedure MyThread(semaphore)
Protected time = ElapsedMilliseconds() + 10000
Protected loop = 0
Repeat
If time > ElapsedMilliseconds()
Debug loop
time = ElapsedMilliseconds() + 10000
EndIf
loop + 1
Delay(1)
Until TrySemaphore(semaphore)
EndProcedure
OpenWindow(0, #PB_Ignore, #PB_Ignore, 140, 80, "bla")
ButtonGadget(0, 5, 5, 100, 20, "start")
ButtonGadget(1, 5, 30, 100, 20, "stop")
DisableGadget(1, #True)
Define semaphore = CreateSemaphore()
Define thread
Repeat
Select WaitWindowEvent()
Case #PB_Event_CloseWindow
Break
Case #PB_Event_Gadget
Select EventGadget()
Case 0
DisableGadget(0, #True)
thread = CreateThread(@MyThread(), semaphore)
DisableGadget(1, #False)
Case 1
SignalSemaphore(semaphore)
WaitThread(thread, 2000)
DisableGadget(1, #True)
DisableGadget(0, #False)
EndSelect
EndSelect
ForEver
Re: KillThread
Verfasst: 04.03.2012 18:53
von Daffy0815
@ts-soft
Schönes Beispiel für die Verwendung von Semaphore aber leider keine Lösung für mein Problem.
Fügen Sie doch mal vor "loop +1" (wusste gar nicht das das geht) "While 0=0 : Wend" ein und versuchen Sie dann mal den Thread zu beenden.
Das ginge nur wenn zwischen While und Wend eine Abfrage wäre die dann mit Break die Schleife verlässt.
Gibt es denn wenigstens so etwas wie "ExitProcedure" ?
(Könnte man natürlich mit dem allseits verpönten "GoTo" zum Ende der Procedur lösen)
Gruß
Daffy
Re: KillThread
Verfasst: 04.03.2012 18:54
von RSBasic
ProcedureReturn
Re: KillThread
Verfasst: 04.03.2012 18:57
von Daffy0815
@RSBasic
Aha, ich dachte das wäre nur die Übergabe des Rückgabewertes.
Danke!
Gruß
Daffy
Re: KillThread
Verfasst: 04.03.2012 19:03
von ts-soft
Verstehe das Problem nicht, wäre dann logischerweise:
Ansonsten kann man, wie bereits gesagt, mit ProcedureReturn
jede Procedure beenden, wobei dies bei Treads sehr unüblich ist.
Re: KillThread
Verfasst: 04.03.2012 20:15
von Daffy0815
Das mit dem ProcedureReturn hat auch nicht vernünftig funktioniert!
Beim erneuten Start des Threads kam es zu sporadischen Austeigern aus dem Programm.
Ich habe es jetzt halt doch auf die Art mit den tausend Abfragen gemacht (was ich persönlich doof finde - Ich liebe Assembler!)
Hier das reale Beispiel (nicht lauffähig):
Code: Alles auswählen
#WartezeitMinMaxdruck = 5000 ;mSek
#AufloesungDAWandler = 16384 ;Bit
Procedure ErzeugeDrucktabelleThread(*Dummy)
;
Debug "DrucktabelleThread"
ExitDrucktabelleThread.i = #False
IstdruckRefresh.i = #False
SysParDrucktabelleGueltig.d = #False
SetSysPar(#RegSysParDrucktabelleGueltig, SysParDrucktabelleGueltig.d)
SetDOut(#AbsperrventilY3, 1) ;schließen
SetDOut(#PruefdruckventilY2, 1) ;öffnen
;
IndexDrucktabelle.i = 0
SolldruckStart.d = MinDruckDrucksystem.d
SolldruckEnde.d = MaxDruckDrucksystem.d
SolldruckStufung.d = Pow(10, -#AnzahlNachkommastellenDrucksystem)
;
StelldruckStart.d = SysParAnOut00Min.d
StelldruckEnde.d = SysParAnOut00Max.d
StelldruckStufung.d = (StelldruckEnde.d - StelldruckStart.d) / #AufloesungDAWandler
;
Debug "SolldruckStart____="+StrD(SolldruckStart.d)
Debug "SolldruckEnde_____="+StrD(SolldruckEnde.d)
Debug "SolldruckStufung__="+StrD(SolldruckStufung.d)
;
If ExitDrucktabelleThread.i <> #True
If SolldruckStart.d >= 0 And SolldruckEnde.d > 0 ;Nur Überdruck
Debug "Nur Überdruck"
SetDOut(#VakuumventilY8, 0)
;
Debug "Maxdruck prüfen"
SolldruckMax.d = SolldruckEnde.d
SetSolldruck(SolldruckMax.d)
SetStelldruck(StelldruckEnde.d)
Wait.i = ElapsedMilliseconds() + #WartezeitMinMaxdruck
While Istdruck.d < SolldruckMax.d
If ExitDrucktabelleThread.i = #True : Break : EndIf
If ElapsedMilliseconds() > Wait.i
RaiseError(#ERROR_MaxDruckNichtErreicht)
EndIf
;Delay(#DelayDrucktabelleThread)
Istdruck.d = GetIstdruck()
Wend
If ExitDrucktabelleThread.i <> #True
Debug "MaxDruck OK"
Debug "Mindruck prüfen"
SolldruckMin.d = SysParDruckgrenzePositiv.d + SolldruckStufung.d
SetSolldruck(SolldruckMin.d)
SetStelldruck(StelldruckStart.d)
Wait.i = ElapsedMilliseconds() + #WartezeitMinMaxdruck
While Istdruck.d > SolldruckMin.d
If ExitDrucktabelleThread.i = #True : Break : EndIf
If ElapsedMilliseconds() > Wait.i
RaiseError(#ERROR_MinDruckNichtErreicht)
EndIf
;Delay(#DelayDrucktabelleThread)
Istdruck.d = GetIstdruck()
Wend
EndIf
If ExitDrucktabelleThread.i <> #True
Debug "Mindruck OK"
SolldruckStart.d = SysParDruckgrenzePositiv.d + SolldruckStufung.d
Solldruck.d = SolldruckStart.d
Stelldruck.d = StelldruckStart.d
While Solldruck.d < SolldruckEnde.d
If ExitDrucktabelleThread.i = #True : Break : EndIf
SetSolldruck(Solldruck.d)
If Istdruck.d > Solldruck.d : RaiseError(#ERROR_IstdruckGroesserSolldruck) : EndIf
If ExitDrucktabelleThread.i <> #True
While Istdruck.d < Solldruck.d
If ExitDrucktabelleThread.i = #True : Break : EndIf
Stelldruck.d = Stelldruck.d + StelldruckStufung.d
;Debug "Stelldruck________="+StrD(Stelldruck.d)
If Stelldruck.d > StelldruckEnde.d : RaiseError(#ERROR_SolldruckNichtErreichbar) : EndIf
SetStelldruck(Stelldruck.d)
;Delay(#DelayDrucktabelleThread)
Istdruck.d = GetIstdruck()
Wend
EndIf
If ExitDrucktabelleThread.i <> #True
;Hier Stelldruck speichern
Drucktabelle.w(IndexDrucktabelle.i) = Round(Stelldruck.d * 1000, #PB_Round_Nearest)
Debug "StelldruckInt_____="+Str(Drucktabelle.w(IndexDrucktabelle.i))
IndexDrucktabelle.i = IndexDrucktabelle.i + 1
;
Solldruck.d = Solldruck.d + SolldruckStufung.d
EndIf
Wend
EndIf
EndIf
EndIf
;
;
;
If ExitDrucktabelleThread.i <> #True
If SolldruckStart.d < 0 And SolldruckEnde.d <= 0 ;Nur Unterdruck
Debug "Nur Unterdruck"
SetDOut(#VakuumventilY8, 1)
;
Debug "Mindruck prüfen"
SolldruckMin.d = SolldruckStart.d
SetSolldruck(SolldruckMin.d)
SetStelldruck(StelldruckEnde.d)
Wait.i = ElapsedMilliseconds() + #WartezeitMinMaxdruck
While Istdruck.d > SolldruckMin.d
If ExitDrucktabelleThread.i = #True : Break : EndIf
If ElapsedMilliseconds() > Wait.i
RaiseError(#ERROR_MinDruckNichtErreicht)
EndIf
;Delay(#DelayDrucktabelleThread)
Istdruck.d = GetIstdruck()
Wend
Debug "Mindruck OK"
If ExitDrucktabelleThread.i <> #True
Debug "Maxdruck prüfen"
SolldruckMax.d = SysParDruckgrenzeNegativ.d - SolldruckStufung.d
SetSolldruck(SolldruckMax.d)
SetStelldruck(StelldruckStart.d)
Wait.i = ElapsedMilliseconds() + #WartezeitMinMaxdruck
While Istdruck.d < SolldruckMax.d
If ExitDrucktabelleThread.i = #True : Break : EndIf
If ElapsedMilliseconds() > Wait.i
RaiseError(#ERROR_MaxDruckNichtErreicht)
EndIf
;Delay(#DelayDrucktabelleThread)
Istdruck.d = GetIstdruck()
Wend
EndIf
If ExitDrucktabelleThread.i <> #True
Debug "MaxDruck OK"
SolldruckStart.d = SysParDruckgrenzeNegativ.d - SolldruckStufung.d
Solldruck.d = SolldruckStart.d
Stelldruck.d = StelldruckStart.d
While Solldruck.d < SolldruckEnde.d
If ExitDrucktabelleThread.i = #True : Break : EndIf
SetSolldruck(Solldruck.d)
If Istdruck.d < Solldruck.d : RaiseError(#ERROR_IstdruckKleinerSolldruck) : EndIf
If ExitDrucktabelleThread.i <> #True
While Istdruck.d > Solldruck.d
If ExitDrucktabelleThread.i = #True : Break : EndIf
Stelldruck.d = Stelldruck.d + StelldruckStufung.d
;Debug "Stelldruck________="+StrD(Stelldruck.d)
If Stelldruck.d > StelldruckEnde.d : RaiseError(#ERROR_SolldruckNichtErreichbar) : EndIf
SetStelldruck(Stelldruck.d)
;Delay(#DelayDrucktabelleThread)
Istdruck.d = GetIstdruck()
Wend
EndIf
If ExitDrucktabelleThread.i <> #True
;Hier Stelldruck speichern
Drucktabelle.w(IndexDrucktabelle.i) = Round(Stelldruck.d * 1000, #PB_Round_Nearest) * -1
Debug "StelldruckInt_____="+Str(Drucktabelle.w(IndexDrucktabelle.i))
IndexDrucktabelle.i = IndexDrucktabelle.i + 1
;
Solldruck.d = Solldruck.d - SolldruckStufung.d
EndIf
Wend
EndIf
EndIf
EndIf
;
;
;
If ExitDrucktabelleThread.i <> #True
If SolldruckStart.d < 0 And SolldruckEnde.d > 0 ;Unterdruck und Überdruck
Debug "Unterdruck und Überdruck"
SetDOut(#VakuumventilY8, 1)
;
Debug "Mindruck prüfen"
SolldruckMin.d = SolldruckStart.d
SetSolldruck(SolldruckMin.d)
SetStelldruck(StelldruckEnde.d)
Wait.i = ElapsedMilliseconds() + #WartezeitMinMaxdruck
While Istdruck.d > SolldruckMin.d
If ExitDrucktabelleThread.i = #True : Break : EndIf
If ElapsedMilliseconds() > Wait.i
RaiseError(#ERROR_MinDruckNichtErreicht)
EndIf
;Delay(#DelayDrucktabelleThread)
Istdruck.d = GetIstdruck()
Wend
If ExitDrucktabelleThread.i <> #True
Debug "Mindruck OK"
SetDOut(#VakuumventilY8, 0)
Debug "Maxdruck prüfen"
SolldruckMax.d = SolldruckEnde.d
SetSolldruck(SolldruckMax.d)
SetStelldruck(StelldruckEnde.d)
Wait.i = ElapsedMilliseconds() + #WartezeitMinMaxdruck
While Istdruck.d < SolldruckMax.d
If ExitDrucktabelleThread.i = #True : Break : EndIf
If ElapsedMilliseconds() > Wait.i
RaiseError(#ERROR_MaxDruckNichtErreicht)
EndIf
;Delay(#DelayDrucktabelleThread)
Istdruck.d = GetIstdruck()
Wend
EndIf
If ExitDrucktabelleThread.i <> #True
Debug "MaxDruck OK"
SetDOut(#VakuumventilY8, 1)
SolldruckStart.d = SysParDruckgrenzeNegativ.d - SolldruckStufung.d
Solldruck.d = SolldruckStart.d
Stelldruck.d = StelldruckStart.d
While Solldruck.d < SolldruckEnde.d
If ExitDrucktabelleThread.i = #True : Break : EndIf
SetSolldruck(Solldruck.d)
If Istdruck.d < Solldruck.d : RaiseError(#ERROR_IstdruckKleinerSolldruck) : EndIf
If ExitDrucktabelleThread.i <> #True
While Istdruck.d > Solldruck.d
If ExitDrucktabelleThread.i = #True : Break : EndIf
Stelldruck.d = Stelldruck.d + StelldruckStufung.d
;Debug "Stelldruck________="+StrD(Stelldruck.d)
If Stelldruck.d > StelldruckEnde.d : RaiseError(#ERROR_SolldruckNichtErreichbar) : EndIf
SetStelldruck(Stelldruck.d)
;Delay(#DelayDrucktabelleThread)
Istdruck.d = GetIstdruck()
Wend
EndIf
If ExitDrucktabelleThread.i <> #True
;Hier Stelldruck speichern
Drucktabelle.w(IndexDrucktabelle.i) = Round(Stelldruck.d * 1000, #PB_Round_Nearest) * -1
Debug "StelldruckInt_____="+Str(Drucktabelle.w(IndexDrucktabelle.i))
IndexDrucktabelle.i = IndexDrucktabelle.i + 1
;
Solldruck.d = Solldruck.d - SolldruckStufung.d
EndIf
Wend
EndIf
;
If ExitDrucktabelleThread.i <> #True
Druckfenster.d = SysParDruckgrenzeNegativ.d
While Druckfenster.d <= SysParDruckgrenzePositiv.d
If ExitDrucktabelleThread.i = #True : Break : EndIf
Drucktabelle.w(IndexDrucktabelle.i) = 0
Debug "StelldruckInt_____="+Str(Drucktabelle.w(IndexDrucktabelle.i))
IndexDrucktabelle.i = IndexDrucktabelle.i + 1
Wend
EndIf
;
If ExitDrucktabelleThread.i <> #True
SetDOut(#VakuumventilY8, 0)
SolldruckStart.d = SysParDruckgrenzePositiv.d + SolldruckStufung.d
Solldruck.d = SolldruckStart.d
Stelldruck.d = StelldruckStart.d
While Solldruck.d < SolldruckEnde.d
If ExitDrucktabelleThread.i = #True : Break : EndIf
SetSolldruck(Solldruck.d)
If Istdruck.d > Solldruck.d : RaiseError(#ERROR_IstdruckGroesserSolldruck) : EndIf
If ExitDrucktabelleThread.i <> #True
While Istdruck.d < Solldruck.d
If ExitDrucktabelleThread.i = #True : Break : EndIf
Stelldruck.d = Stelldruck.d + StelldruckStufung.d
;Debug "Stelldruck________="+StrD(Stelldruck.d)
If Stelldruck.d > StelldruckEnde.d : RaiseError(#ERROR_SolldruckNichtErreichbar) : EndIf
SetStelldruck(Stelldruck.d)
;Delay(#DelayDrucktabelleThread)
Istdruck.d = GetIstdruck()
Wend
EndIf
If ExitDrucktabelleThread.i <> #True
;Hier Stelldruck speichern
Drucktabelle.w(IndexDrucktabelle.i) = Round(Stelldruck.d * 1000, #PB_Round_Nearest)
Debug "StelldruckInt_____="+Str(Drucktabelle.w(IndexDrucktabelle.i))
IndexDrucktabelle.i = IndexDrucktabelle.i + 1
;
Solldruck.d = Solldruck.d + SolldruckStufung.d
EndIf
Wend
EndIf
EndIf
EndIf
If ExitDrucktabelleThread.i <> #True
;
;Hier Drucktabelle an Basisplatine senden
SysParAnzahlWerteDrucktabelle.d = IndexDrucktabelle.i
SysParMinDruckDrucktabelle.d = SolldruckStart.d
SysParMaxDruckDrucktabelle.d = SolldruckEnde.d
SetSysPar(#RegSysParAnzahlWerteDrucktabelle, SysParAnzahlWerteDrucktabelle.d)
SetSysPar(#RegSysParMinDruckDrucktabelle, SysParMinDruckDrucktabelle.d)
SetSysPar(#RegSysParMaxDruckDrucktabelle, SysParMaxDruckDrucktabelle.d)
;
SetControlVar(#RegCtrlVarRun, #RunSetDrkTab)
;
For Index.i = 0 To SysParAnzahlWerteDrucktabelle.d - 1
SetControlVar(#RegCtrlVarValue, Drucktabelle.w(Index.i))
WaitControlVar(#RegCtrlVarValue, -32768)
Debug "Index="+Str(Index.i)
Next
SetControlVar(#RegCtrlVarRun, #RunDoNothing)
;
SysParDrucktabelleGueltig.d = #FlagDrucktabelleGueltig
SetSysPar(#RegSysParDrucktabelleGueltig, SysParDrucktabelleGueltig.d)
EndIf
;
SetDOut(#PruefdruckventilY2, 0)
SetDOut(#AbsperrventilY3, 0)
SetDOut(#VakuumventilY8, 0)
IstdruckRefresh.i = #True
EndProcedure
Gruß
Daffy
Re: KillThread
Verfasst: 04.03.2012 20:47
von Thorium
Das ProcedureReturn nicht funktioniert ist aber merkwürdig. Das dürfte ein Bug sein. Denn ein Rücksprung aus einem Thread ist durchaus möglich. Auf dem Stack liegt nach erstellen des Threads nämlich eine gültige Rücksprungadresse in die Kernel32.dll wo der Thread dann ordnungsgemäß beendet wird. Jedenfall wenn wir von Windows reden.
Ansonsten kannst du auch ExitThread_(ExitCode) unter Windows verwenden um den Thread sich selbst beenden zu lassen.
Zu den sporadischen Aussteigern: Hast du Threadsafe aktiviert? Das muss zwingend aktiviert werden, wenn du mit Strings in Threads arbeitest.
Re: KillThread
Verfasst: 04.03.2012 21:02
von Daffy0815
@Thorium
Das ist gut möglich denn das mit dem "IstDruckRefresh.i" habe ich erst später eingebaut weil GetIstDruck auch vom Hauptprogramm (das ja im Hintergrund weiterläuft) aufgerufen wird. Und da hätte sich durchaus etwas "verheddern" können.
IstDruckRefresh.i sperrt nun die Abfrage im Hauptprogramm solange der Thread läuft.
Das mit dem "ExitThread_" ist schon mal ganz gut hat aber noch einen kleinen Haken.
So wie das jetzt geschieben ist, werden beim Abbruch des Threads immer alle Ventile geschlossen.
Würde man es mit dem ExitThread_ machen, so ginge das dann nur mit dem ExitCode und da müsste man wieder im Hauptprogramm eine Abfrage einbauen.
Wäre aber bestimmt einfacher als die jetzige Lösung!
Ideal wäre eigentlich "KillThread Goto ..."
Gruß
Daffy