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:

Code: Alles auswählen

While TrySemaphore(semaphore) = 0 : Wend
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