Thread scheint stehen zu bleiben

Anfängerfragen zum Programmieren mit PureBasic.
Benutzeravatar
The_Dark_Zim-.-
Beiträge: 372
Registriert: 18.03.2008 16:53

Thread scheint stehen zu bleiben

Beitrag von The_Dark_Zim-.- »

Hey,

ich versuche mich gerade mit Threads. Leider klapt es nicht so ganz. Es scheint als würde der eine Thread stehen bleiben oder er bekommt keinen Zugriff auf eine Globale Variable?!

Ich habe eine Hauptschleife aus der ich eine Variable umsetze (window) dann gehe ich eine Warte schleife wo ich drauf warte das der andere Thread eine Variable (ThreadRunning ) auf False setzt weil Window nicht mehr 0 ist. Das geht aber nicht immer, heisst es geht z.b. 10 mal und dann bleibt er in der Warte schleife hängen, Sprich ThreadRunning wird nicht auf False gesetzt.

Hier so in etwa läuft meine Software ab.

Code: Alles auswählen

Procedure WaitForThread()
  
  While ThreadRunning = #True
    Delay(5)
  Wend
  
EndProcedure 

Procedure SetStatusDate(ThreadWert)
   
  Repeat
    
    If window = 0
      
      ThreadRunning = #True
      
      ...
      
    Else
      ThreadRunning = #False
    EndIf
    
  Until CloseSoftware = #True
  
  ThreadRunning = #False
  
EndProcedure

CreateThread(@SetStatusDate(), 0)

Repeat
  
  Select Window
    Case 0
....

  EndSelect
  
Until CloseSoftware = #True

WaitForThread()

PB: 5.xx LTS x86/x64 | WIN: 10 Pro x64, Linux Mint x64
Benutzeravatar
STARGÅTE
Kommando SG1
Beiträge: 7031
Registriert: 01.11.2005 13:34
Wohnort: Glienicke
Kontaktdaten:

Re: Thread scheint stehen zu bleiben

Beitrag von STARGÅTE »

The_Dark_Zim-.- hat geschrieben:Hier so in etwa läuft meine Software ab.
Das reicht leider nicht, um dein Problem zu reproduzieren.

Hier eine Information:
Es gibt WaitThread() von PureBasic, um auf das Ende eines Threads zu warten.
PB 6.01 ― Win 10, 21H2 ― Ryzen 9 3900X, 32 GB ― NVIDIA GeForce RTX 3080 ― Vivaldi 6.0 ― www.unionbytes.de
Aktuelles Projekt: Lizard - Skriptsprache für symbolische Berechnungen und mehr
Benutzeravatar
The_Dark_Zim-.-
Beiträge: 372
Registriert: 18.03.2008 16:53

Re: Thread scheint stehen zu bleiben

Beitrag von The_Dark_Zim-.- »

Ich hatte gedacht das ich generell was falsch mache, darum hatte ich nur grob gezeigt was ich mache.

So ich hoffe das reicht euch :)

Code: Alles auswählen

Global SerialPortName$, Baud, Parity, DataLength, Stop.f, HandshakeMode, InputBufferSize, OutputBufferSize, Terminator$

Global Window_0

Global Button_0

Global ThreadRunning, CloseSoftware = #False

Global Window = 0

SerialPortName$ = "Com1"
Baud = 9600
Parity = #PB_SerialPort_NoParity
DataLength = 8
Stop = 2
HandshakeMode = #PB_SerialPort_NoHandshake
InputBufferSize = 1024
outputBufferSize = 1024
Terminator$ = ""

#SerialPort = 0

Procedure WaitForThread()
  
  While ThreadRunning = #True
    Delay(5)
  Wend
  
EndProcedure  

Procedure.l OpenRsPort()
  
  ProcedureReturn OpenSerialPort(#SerialPort, SerialPortName$, Baud, Parity, DataLength, Stop.f, HandshakeMode, InputBufferSize, OutputBufferSize)
  
EndProcedure

Procedure IsRsPort()
  
  If IsSerialPort(#SerialPort)
    ProcedureReturn 1
  Else
    ProcedureReturn OpenRsPort()
  EndIf
    
EndProcedure

Procedure.l WriteRsString(String$)
  
  If IsRsPort()
  
    ReturnValue = WriteSerialPortString(#SerialPort, String$ + Terminator$)
  
  Else
    
    ReturnValue = 0
      
  EndIf

  ProcedureReturn ReturnValue
  
EndProcedure

Procedure.s ReadRsString()
  
  If IsRsPort()
  
    While Wait < 149
      
      Buffer = AvailableSerialPortInput(#SerialPort)
      
      If Buffer > 0
        
        While Buffer > 0
          ReadSerialPortData(#SerialPort,@RD,1)
          Receive$ + Chr(RD)
          
          Buffer = AvailableSerialPortInput(#SerialPort)
          
          If Buffer < 2
            Delay(5)
            Buffer = AvailableSerialPortInput(#SerialPort)
          EndIf
        Wend
        
      Else
        Wait+1
        Delay(1)
      EndIf
      
    Wend
    
  EndIf
  
  ProcedureReturn Receive$
  
EndProcedure

Procedure OpenWindow_0()
  Window_0 = OpenWindow(#PB_Any, 0, 0, 340, 280, "Thread_Test", #PB_Window_SystemMenu)
  CreateStatusBar(0, WindowID(Window_0))
  AddStatusBarField(50)
  StatusBarText(0, 0, "Label")
  AddStatusBarField(50)
  StatusBarText(0, 1, "Label")
  AddStatusBarField(50)
  StatusBarText(0, 2, "Label")
  AddStatusBarField(50)
  StatusBarText(0, 3, "Label")
  Button_0 = ButtonGadget(#PB_Any, 130, 100, 70, 30, "test")
EndProcedure

Procedure Window_0_Events(event)
  Select event
    Case #PB_Event_CloseWindow
      ProcedureReturn #False

    Case #PB_Event_Menu
      Select EventMenu()
      EndSelect

    Case #PB_Event_Gadget
      Select EventGadget()
        Case Button_0
          Window = 2
          WaitForThread()
          Debug("test")
          Window = 0
      EndSelect
  EndSelect
  ProcedureReturn #True
EndProcedure

Procedure SetStatusState(Boolean.b)
  
  If Connected
    If Boolean = #False
      
      StatusBarImage(0, 0, ImageID(Img_0))
      StatusBarText(0, 1, "Nicht verbunden")
      
      Connected = #False
    EndIf
  Else
    If Boolean
      
      StatusBarImage(0, 0, ImageID(Img_101))
      StatusBarText(0, 1, "Verbunden")
           
      Connected = #True
    EndIf
  EndIf
  
EndProcedure

Procedure SetStatusDate(ThreadWert)
   
  Repeat
    
    If window = 0
      
      ThreadRunning = #True
      
      If Time >= 40
        Time = 0
        
        WriteRsString("UL")
        
        Receive$ = ReadRsString()
        
        If Receive$ <> ""
          Receive$ = RemoveString(Receive$, ":")
          StatusTime$ = Left(Receive$, 6)
          StatusTime$ = InsertString(StatusTime$, ":", 5)
          StatusTime$ = InsertString(StatusTime$, ":", 3)
          
          If OldStatusTime$ <> StatusTime$
            StatusBarText(0, 3, StatusTime$ + " Uhr")
            OldStatusTime$ = StatusTime$
          EndIf
          
          StatusDate$ = Right(Receive$, 8)
          
          Select DayOfWeek(Date(Val(Right(StatusDate$, 4)), Val(Mid(StatusDate$, 3, 2)), Val(Left(StatusDate$, 2)), 0, 0, 0))
            Case 0 
              Day$ = "Sonntag"
            Case 1 
              Day$ = "Montag"
            Case 2 
              Day$ = "Dienstag"
            Case 3 
              Day$ = "Mittwoch"
            Case 4 
              Day$ = "Donnerstag"
            Case 5 
              Day$ = "Freitag"
            Case 6 
              Day$ = "Samstag"
          EndSelect
          
          Select Val(Mid(StatusDate$, 3, 2))
            Case 1
              Month$ = "Januar"
            Case 2
              Month$ = "Februar"
            Case 3
              Month$ = "März"
            Case 4
              Month$ = "April"
            Case 5
              Month$ = "Mai"
            Case 6
              Month$ = "Juni"
            Case 7
              Month$ = "Juli"
            Case 8
              Month$ = "August"
            Case 9
              Month$ = "September"
            Case 10
              Month$ = "Oktober"
            Case 11
              Month$ = "November"
            Case 12
              Month$ = "Dezember"
          EndSelect
          
          StatusDate$ = Day$ + " den " + Left(StatusDate$, 2)  + " " + Month$ + " " + Right(StatusDate$, 4)
          
          If StatusDate$ <> OldStatusDate$
            StatusBarText(0, 2, StatusDate$)
            OldStatusDate$ = StatusDate$
          EndIf
          
          SetStatusState(#True)
          
        Else
          
          CloseSerialPort(#SerialPort)
          
          Select DayOfWeek(Date())
            Case 0 
              Day$ = "Sonntag"
            Case 1 
              Day$ = "Montag"
            Case 2 
              Day$ = "Dienstag"
            Case 3 
              Day$ = "Mittwoch"
            Case 4 
              Day$ = "Donnerstag"
            Case 5 
              Day$ = "Freitag"
            Case 6 
              Day$ = "Samstag"
          EndSelect
          
          Select Month(Date())
            Case 1
              Month$ = "Januar"
            Case 2
              Month$ = "Februar"
            Case 3
              Month$ = "März"
            Case 4
              Month$ = "April"
            Case 5
              Month$ = "Mai"
            Case 6
              Month$ = "Juni"
            Case 7
              Month$ = "Juli"
            Case 8
              Month$ = "August"
            Case 9
              Month$ = "September"
            Case 10
              Month$ = "Oktober"
            Case 11
              Month$ = "November"
            Case 12
              Month$ = "Dezember"
          EndSelect
          
          StatusDate$ = Day$ + " den " +  FormatDate("%dd. ", Date()) + Month$ + FormatDate(" %yyyy", Date())
          
          If StatusDate$ <> OldStatusDate$
            StatusBarText(0, 2, StatusDate$)
            OldStatusDate$ = StatusDate$
          EndIf
          
          StatusTime$ = FormatDate("%hh:%ii:%ss", Date())
          
          If OldStatusTime$ <> StatusTime$
            StatusBarText(0, 3, StatusTime$ + " Uhr")
            OldStatusTime$ = StatusTime$
          EndIf
          
          SetStatusState(#False)
        EndIf
        
      Else
        Time +1
      EndIf
      
      Delay(25)
      
    Else
      ThreadRunning = #False
    EndIf
    
  Until CloseSoftware = #True
  
  ThreadRunning = #False
  
EndProcedure

OpenWindow_0()

CreateThread(@SetStatusDate(), 0)

Repeat
  
  Select Window
    Case 0
      If Window_0_Events(WaitWindowEvent(25)) = #False
        CloseSoftware = #True
      EndIf
;     Case 1
;       If Window_1_Events(WaitWindowEvent(25)) = #False
;         Close(Window)
;       EndIf
;     Case 2
;       If Window_2_Events(WaitWindowEvent(25)) = #False
;         Close(Window)
;       EndIf
;     Case 3
;       If Window_3_Events(WaitWindowEvent(25)) = #False
;         Close(Window)
;       EndIf
;     Case 4
;       If Window_4_Events(WaitWindowEvent(25)) = #False
;         Close(Window)
;       EndIf
;     Case 5
;       Event = WaitWindowEvent(25)
;       If Event = #PB_Event_SizeWindow
;         Window_5_Events(Event)
;         ZeichneKurve()
;       Else
;        If Window_5_Events(Event) = #False
;          Close(Window)
;        EndIf
;       EndIf
;     Case 6
;       If Window_6_Events(WaitWindowEvent(25)) = #False
;         Close(Window)
;       EndIf
;     Case 7
;       If Window_7_Events(WaitWindowEvent(25)) = #False
;         Close(Window)
;       EndIf
;     Case 8
;       If Window_8_Events(WaitWindowEvent(25)) = #False
;         Close(Window)
;       EndIf
  EndSelect
  
Until CloseSoftware = #True

WaitForThread()
PB: 5.xx LTS x86/x64 | WIN: 10 Pro x64, Linux Mint x64
Benutzeravatar
STARGÅTE
Kommando SG1
Beiträge: 7031
Registriert: 01.11.2005 13:34
Wohnort: Glienicke
Kontaktdaten:

Re: Thread scheint stehen zu bleiben

Beitrag von STARGÅTE »

Ich sehe an der Variable 'window' ein Problem.
Denn diese könnte im Hauptprogramm genau im falschen Moment auf window = 2 gesetzt werden.
Nämlich genau dann, wenn der Thread bereits im 'If window = 0' hineingegangen ist.

Fest steht dass ThreadRunning nicht auf #False gesetzt wird, weil der in einer Funktion im Thread hängen bleibt.
PB 6.01 ― Win 10, 21H2 ― Ryzen 9 3900X, 32 GB ― NVIDIA GeForce RTX 3080 ― Vivaldi 6.0 ― www.unionbytes.de
Aktuelles Projekt: Lizard - Skriptsprache für symbolische Berechnungen und mehr
Benutzeravatar
The_Dark_Zim-.-
Beiträge: 372
Registriert: 18.03.2008 16:53

Re: Thread scheint stehen zu bleiben

Beitrag von The_Dark_Zim-.- »

Ja sowas hab ich mir schon gedacht. Wie kann man denn sowas lösen?
PB: 5.xx LTS x86/x64 | WIN: 10 Pro x64, Linux Mint x64
Benutzeravatar
NicTheQuick
Ein Admin
Beiträge: 8809
Registriert: 29.08.2004 20:20
Computerausstattung: Ryzen 7 5800X, 64 GB DDR4-3200
Ubuntu 24.04.2 LTS
GeForce RTX 3080 Ti
Wohnort: Saarbrücken

Re: Thread scheint stehen zu bleiben

Beitrag von NicTheQuick »

Normalerweise löst man solche Probleme mit Locks, also Mutexen und Semaphoren. In der Hilfe von PB stehen eigentlich ein paar gute Beispiele dazu.
Benutzeravatar
The_Dark_Zim-.-
Beiträge: 372
Registriert: 18.03.2008 16:53

Re: Thread scheint stehen zu bleiben

Beitrag von The_Dark_Zim-.- »

Hm hab mir das mal angesehen und versucht um zu setzen. Scheint mir aber nicht gelungen zu sein, läuft nun sogar schlechter als vorher Oo was mache ich falsch?

Code: Alles auswählen

Global SerialPortName$, Baud, Parity, DataLength, Stop.f, HandshakeMode, InputBufferSize, OutputBufferSize, Terminator$

Global Window_0

Global Button_0, Time, OldStatusDate$

Global ThreadRunning, CloseSoftware = #False

Global Window = 0

SerialPortName$ = "Com1"
Baud = 9600
Parity = #PB_SerialPort_NoParity
DataLength = 8
Stop = 2
HandshakeMode = #PB_SerialPort_NoHandshake
InputBufferSize = 1024
outputBufferSize = 1024
Terminator$ = ""

#SerialPort = 0

Procedure ThreadRunning(Write.b, Value.b)
  Shared Mutex
  
  LockMutex(Mutex)
  
  If Write
    ThreadRunning = Value
  EndIf
  
  UnlockMutex(Mutex)
  
  ProcedureReturn ThreadRunning
  
EndProcedure

Procedure ThreadWindow(Write.b, Value)
  Shared Mutex
  
  LockMutex(Mutex)
  
  If Write
    Window = Value
  EndIf
  
  UnlockMutex(Mutex)
  
  ProcedureReturn Window
  
EndProcedure

Procedure WaitForThread()
  
  While ThreadRunning(#False, #False)
    Delay(5)
  Wend
  
EndProcedure  

Procedure.l OpenRsPort()
  
  ProcedureReturn OpenSerialPort(#SerialPort, SerialPortName$, Baud, Parity, DataLength, Stop.f, HandshakeMode, InputBufferSize, OutputBufferSize)
  
EndProcedure

Procedure IsRsPort()
  
  If IsSerialPort(#SerialPort)
    ProcedureReturn 1
  Else
    ProcedureReturn OpenRsPort()
  EndIf
    
EndProcedure

Procedure.l WriteRsString(String$)
  
  If IsRsPort()
  
    ReturnValue = WriteSerialPortString(#SerialPort, String$ + Terminator$)
  
  Else
    
    ReturnValue = 0
      
  EndIf

  ProcedureReturn ReturnValue
  
EndProcedure

Procedure.s ReadRsString()
  
  If IsRsPort()
  
    While Wait < 149
      
      Buffer = AvailableSerialPortInput(#SerialPort)
      
      If Buffer > 0
        
        While Buffer > 0
          ReadSerialPortData(#SerialPort,@RD,1)
          Receive$ + Chr(RD)
          
          Buffer = AvailableSerialPortInput(#SerialPort)
          
          If Buffer < 2
            Delay(5)
            Buffer = AvailableSerialPortInput(#SerialPort)
          EndIf
        Wend
        
      Else
        Wait+1
        Delay(1)
      EndIf
      
    Wend
    
  EndIf
  
  ProcedureReturn Receive$
  
EndProcedure

Procedure OpenWindow_0()
  Window_0 = OpenWindow(#PB_Any, 0, 0, 340, 280, "Thread_Test", #PB_Window_SystemMenu)
  CreateStatusBar(0, WindowID(Window_0))
  AddStatusBarField(50)
  StatusBarText(0, 0, "Label")
  AddStatusBarField(50)
  StatusBarText(0, 1, "Label")
  AddStatusBarField(50)
  StatusBarText(0, 2, "Label")
  AddStatusBarField(50)
  StatusBarText(0, 3, "Label")
  Button_0 = ButtonGadget(#PB_Any, 130, 100, 70, 30, "test")
EndProcedure

Procedure Window_0_Events(event)
  Select event
    Case #PB_Event_CloseWindow
      ProcedureReturn #False

    Case #PB_Event_Menu
      Select EventMenu()
      EndSelect

    Case #PB_Event_Gadget
      Select EventGadget()
        Case Button_0
          ThreadWindow(#True, 2)
          WaitForThread()
          Debug("test")
          ThreadWindow(#True, 0)
      EndSelect
  EndSelect
  ProcedureReturn #True
EndProcedure

Procedure SetStatusState(Boolean.b)
  
  If Connected
    If Boolean = #False
      
      StatusBarImage(0, 0, ImageID(Img_0))
      StatusBarText(0, 1, "Nicht verbunden")
      
      Connected = #False
    EndIf
  Else
    If Boolean
      
      StatusBarImage(0, 0, ImageID(Img_101))
      StatusBarText(0, 1, "Verbunden")
           
      Connected = #True
    EndIf
  EndIf
  
EndProcedure

Procedure SetStatusDate(ThreadWert)
   
  Repeat
    
    If ThreadWindow(#False, 0) = 0
      
      ThreadRunning(#True, #True)
             
        WriteRsString("UL")
        
        Receive$ = ReadRsString()
        
        If Receive$ <> ""
          Receive$ = RemoveString(Receive$, ":")
          StatusTime$ = Left(Receive$, 6)
          StatusTime$ = InsertString(StatusTime$, ":", 5)
          StatusTime$ = InsertString(StatusTime$, ":", 3)
          
          If OldStatusTime$ <> StatusTime$
            StatusBarText(0, 3, StatusTime$ + " Uhr")
            OldStatusTime$ = StatusTime$
          EndIf
          
          StatusDate$ = Right(Receive$, 8)
          
          Select DayOfWeek(Date(Val(Right(StatusDate$, 4)), Val(Mid(StatusDate$, 3, 2)), Val(Left(StatusDate$, 2)), 0, 0, 0))
            Case 0 
              Day$ = "Sonntag"
            Case 1 
              Day$ = "Montag"
            Case 2 
              Day$ = "Dienstag"
            Case 3 
              Day$ = "Mittwoch"
            Case 4 
              Day$ = "Donnerstag"
            Case 5 
              Day$ = "Freitag"
            Case 6 
              Day$ = "Samstag"
          EndSelect
          
          Select Val(Mid(StatusDate$, 3, 2))
            Case 1
              Month$ = "Januar"
            Case 2
              Month$ = "Februar"
            Case 3
              Month$ = "März"
            Case 4
              Month$ = "April"
            Case 5
              Month$ = "Mai"
            Case 6
              Month$ = "Juni"
            Case 7
              Month$ = "Juli"
            Case 8
              Month$ = "August"
            Case 9
              Month$ = "September"
            Case 10
              Month$ = "Oktober"
            Case 11
              Month$ = "November"
            Case 12
              Month$ = "Dezember"
          EndSelect
          
          StatusDate$ = Day$ + " den " + Left(StatusDate$, 2)  + " " + Month$ + " " + Right(StatusDate$, 4)
          
          If StatusDate$ <> OldStatusDate$
            StatusBarText(0, 2, StatusDate$)
            OldStatusDate$ = StatusDate$
          EndIf
          
          SetStatusState(#True)
          
        Else
          
          CloseSerialPort(#SerialPort)
          
          Select DayOfWeek(Date())
            Case 0 
              Day$ = "Sonntag"
            Case 1 
              Day$ = "Montag"
            Case 2 
              Day$ = "Dienstag"
            Case 3 
              Day$ = "Mittwoch"
            Case 4 
              Day$ = "Donnerstag"
            Case 5 
              Day$ = "Freitag"
            Case 6 
              Day$ = "Samstag"
          EndSelect
          
          Select Month(Date())
            Case 1
              Month$ = "Januar"
            Case 2
              Month$ = "Februar"
            Case 3
              Month$ = "März"
            Case 4
              Month$ = "April"
            Case 5
              Month$ = "Mai"
            Case 6
              Month$ = "Juni"
            Case 7
              Month$ = "Juli"
            Case 8
              Month$ = "August"
            Case 9
              Month$ = "September"
            Case 10
              Month$ = "Oktober"
            Case 11
              Month$ = "November"
            Case 12
              Month$ = "Dezember"
          EndSelect
          
          StatusDate$ = Day$ + " den " +  FormatDate("%dd. ", Date()) + Month$ + FormatDate(" %yyyy", Date())
          
          If StatusDate$ <> OldStatusDate$
            StatusBarText(0, 2, StatusDate$)
            OldStatusDate$ = StatusDate$
          EndIf
          
          StatusTime$ = FormatDate("%hh:%ii:%ss", Date())
          
          If OldStatusTime$ <> StatusTime$
            StatusBarText(0, 3, StatusTime$ + " Uhr")
            OldStatusTime$ = StatusTime$
          EndIf
          
          SetStatusState(#False)
        EndIf
      
      Delay(1000)
      
    Else
      ThreadRunning(#True, #False)
    EndIf

  Until CloseSoftware = #True
  
  ThreadRunning(#True, #False)
  
EndProcedure

OpenWindow_0()

Mutex = CreateMutex()

CreateThread(@SetStatusDate(), 0)

Repeat
  
  Select ThreadWindow(#False, 0)
    Case 0
      If Window_0_Events(WaitWindowEvent(25)) = #False
        CloseSoftware = #True
      EndIf
;     Case 1
;       If Window_1_Events(WaitWindowEvent(25)) = #False
;         Close(Window)
;       EndIf
;     Case 2
;       If Window_2_Events(WaitWindowEvent(25)) = #False
;         Close(Window)
;       EndIf
;     Case 3
;       If Window_3_Events(WaitWindowEvent(25)) = #False
;         Close(Window)
;       EndIf
;     Case 4
;       If Window_4_Events(WaitWindowEvent(25)) = #False
;         Close(Window)
;       EndIf
;     Case 5
;       Event = WaitWindowEvent(25)
;       If Event = #PB_Event_SizeWindow
;         Window_5_Events(Event)
;         ZeichneKurve()
;       Else
;        If Window_5_Events(Event) = #False
;          Close(Window)
;        EndIf
;       EndIf
;     Case 6
;       If Window_6_Events(WaitWindowEvent(25)) = #False
;         Close(Window)
;       EndIf
;     Case 7
;       If Window_7_Events(WaitWindowEvent(25)) = #False
;         Close(Window)
;       EndIf
;     Case 8
;       If Window_8_Events(WaitWindowEvent(25)) = #False
;         Close(Window)
;       EndIf
  EndSelect
  
Until CloseSoftware = #True

WaitForThread()
PB: 5.xx LTS x86/x64 | WIN: 10 Pro x64, Linux Mint x64
Antworten