Wie baut man einen Thread richtig auf?

Anfängerfragen zum Programmieren mit PureBasic.
Benutzeravatar
jacdelad
Beiträge: 348
Registriert: 03.02.2021 13:39
Computerausstattung: Ryzen 5800X, 108TB Festplatte, 32GB RAM, Radeon 7770OC
Wohnort: Riesa
Kontaktdaten:

Re: Wie baut man einen Thread richtig auf?

Beitrag von jacdelad »

Code: Alles auswählen

Global thread

Procedure MyThread(dummy)
  Repeat
    Delay(1000)
    Debug "Thread lebt noch!"
  ForEver
EndProcedure

OpenWindow(0,0,0,300,200,"MyWindow",#PB_Window_SystemMenu|#PB_Window_ScreenCentered)
ScrollBarGadget(0,10,10,280,20,0,100,5)

CreateThread(@MyThread(),0)

Repeat
  Select WaitWindowEvent()
    Case #PB_Event_CloseWindow
      Break
    Case #PB_Event_Gadget
      Select EventGadget()
        Case 0
          Debug GetGadgetState(0)
      EndSelect
  EndSelect
ForEver
PureBasic 6.04/XProfan X4a/Embarcadero RAD Studio 11/Perl 5.2/Python 3.10
Windows 11/Ryzen 5800X/32GB RAM/Radeon 7770 OC/3TB SSD/11TB HDD
Synology DS1821+/36GB RAM/130TB
Synology DS920+/20GB RAM/54TB
Synology DS916+ii/8GB RAM/12TB
Re42
Beiträge: 91
Registriert: 08.11.2020 23:41

Re: Wie baut man einen Thread richtig auf?

Beitrag von Re42 »

Es läuft eine For-Next-Schleife und aus dieser heraus wird immerwieder neu der Thread aufgerufen mit Prd(*x). Der Thread selber sieht dann so aus:

Code: Alles auswählen

Procedure Prd(*x)
      Shared starttime
      Shared time
      Shared ggst.d
      Shared svl.d
      Shared count
      
      starttime = ElapsedMilliseconds()
      Repeat
        time = ElapsedMilliseconds()
        ExamineKeyboard()
        
        Select event
          Case #PB_Event_Menu
           Select EventMenu()
             Case #PB_Key_Space
             time = 1200
        EndSelect
        
      Until (time - starttime) > 1100
      count = 0
    EndProcedure
Dadrunter stehen die Anweisungen für den Thread, das ScrollBarGadget und das BindGadgetEvent:

Code: Alles auswählen

ScrollBarGadget(1,1010,25,20,363,1,100,10,#PB_ScrollBar_Vertical) ; 1,1010,19,20,375,1,100,10
   
   CreateThread(@Prd(),1)
   BindGadgetEvent(1, @BindVScrollDatas())
Das ScrollBarGadget läßt sich aber nicht bewegen, solange der Thread läuft. Liegt das an dem Aufruf aus der For-Next-Schleife heraus?
Benutzeravatar
jacdelad
Beiträge: 348
Registriert: 03.02.2021 13:39
Computerausstattung: Ryzen 5800X, 108TB Festplatte, 32GB RAM, Radeon 7770OC
Wohnort: Riesa
Kontaktdaten:

Re: Wie baut man einen Thread richtig auf?

Beitrag von jacdelad »

Du musst schon einen lauffähigen Code posten.
...allerdings ist die Aussage, dass der Thread immer wieder neu gestartet wird schon etwas seltsam. Und im Thread hat EventMenu() nichts zu suchen, das gehört in die Schleife für Events. Ebenso ExamineKeyboard, das ist dort mit 99%-iger Sicherheit falsch.

Poste mal einen lauffähigen Code. Und vielleicht auch mal, was genau gemacht werden soll. Ich hab die Vermutung, dass du vielleicht gar keinen Extra-Thread brauchst.
PureBasic 6.04/XProfan X4a/Embarcadero RAD Studio 11/Perl 5.2/Python 3.10
Windows 11/Ryzen 5800X/32GB RAM/Radeon 7770 OC/3TB SSD/11TB HDD
Synology DS1821+/36GB RAM/130TB
Synology DS920+/20GB RAM/54TB
Synology DS916+ii/8GB RAM/12TB
Benutzeravatar
NicTheQuick
Ein Admin
Beiträge: 8679
Registriert: 29.08.2004 20:20
Computerausstattung: Ryzen 7 5800X, 32 GB DDR4-3200
Ubuntu 22.04.3 LTS
GeForce RTX 3080 Ti
Wohnort: Saarbrücken
Kontaktdaten:

Re: Wie baut man einen Thread richtig auf?

Beitrag von NicTheQuick »

Re42 hat geschrieben: 22.09.2022 15:36 Die Sache hat noch einen weiteren Haken, denn, wenn der Thread läuft, ist das ScrollBarGadget blockiert. Oder kommt man da irgendwie raus?

Und noch etwas möchte ich schon lange beseitigen, auch wenn das jetzt nicht zum Thema gehört: Wie erreicht man in einer Procedure oder Subroutine, daß man auch dann das Fenster bewegen oder schließen kann? Das ist so häßlich, wenn dann jedesmal "Keine Rückmeldung" kommt. Es ist ja wahrscheinlich verpöhnt, Event = WaitWindowEvent(x) mehr als nur einmal in den Code zu schreiben.

Danke.
Du machst sicherlich grundlegend etwas falsch. Am besten postest du mal deinen Code, der die Probleme verursacht.
In der Regel reicht eine Ereignisschleife mit 'WaitWindowEvent()'. Threads blockieren diese ja nicht, dafür sind sie da.

Edit: Hoppla, ich hab die zweite Thread-Seite noch gar nicht gesehen. :lol:
Also in dem Fall schließe ich mich an: Ein lauffähiger Code wäre wichtig.
Bild
Re42
Beiträge: 91
Registriert: 08.11.2020 23:41

Re: Wie baut man einen Thread richtig auf?

Beitrag von Re42 »

Der Aufruf des Threads erfolgt Xmal aus einer For-Next-Schleife heraus. Der Thread sieht so aus:


Code: Alles auswählen

Procedure Prd(*x)
      Shared starttime
      Shared time
      Shared ggst.d
      Shared svl.d
      Shared count
      
      starttime = ElapsedMilliseconds()
      Repeat
        time = ElapsedMilliseconds()
        ExamineKeyboard()
        
        Select event
          Case #PB_Event_Menu
           Select EventMenu()
             Case #PB_Key_Space
             time = 1200
        EndSelect
       
        If KeyboardReleased(#PB_Key_Space) And space = 1
          space = 0 
        EndIf
        If KeyboardPushed(#PB_Key_Space) And space = 0
          StopSound(#PB_All)
          space = 2
          br = 1
          esc = 1
          Break
        EndIf
        
      Until (time - starttime) > 1100
      count = 0
    EndProcedure
Und noch ein paar Programmzeilen weiter unten:

Code: Alles auswählen

Procedure BindVScrollDatas()
     Shared ggst.d
     ggst.d = GetGadgetState(1)
     svl.d = 91 - ggst.d ; 76 - ggst.d
     SoundVolume(#PB_All,svl.d) 
   EndProcedure
  
   ScrollBarGadget(1,1010,25,20,363,1,100,10,#PB_ScrollBar_Vertical)
   
   ggst.d = GetGadgetState(1)
   svl.d = 91 - ggst.d 
   SoundVolume(#PB_All,svl.d)
   
   CreateThread(@Prd(),1)
   BindGadgetEvent(1, @BindVScrollDatas())

Vielleicht ist ja dann das ScollBarGadget blockiert, weil der Thread jedesmal aus einer For-Next-Schleife heraus aufgerufen wird, ich weiß es nicht. Ich werde lauffähigen Code vorbereiten.
Re42
Beiträge: 91
Registriert: 08.11.2020 23:41

Re: Wie baut man einen Thread richtig auf?

Beitrag von Re42 »

Ich werde etwas vorbereiten an Code-Beispiel, aber das schaffe ich jetzt nicht mehr. Nachher ist Dienst, wird also morgen.

Das mit dem zweiten Event = WaitWindowEvent(5) hatte ich gemacht, weil ich auch in der Procedure Abfragen brauche und weil das Fenster nicht "Keine Rückmeldung" ausgeben soll, wenn ich das versuche, zu bewegen, während eine Procedure oder Subroutine durchlaufen wird. In einer zweiten Schleife wird doch das Event = WaitWindowEvent(5) der Hauptschleife erst gar nicht mehr erreicht. Ich habe nie gewußt, wie man aus dem Dilemma anders raus kommen soll als mit Extra Event = WaitWindowEvent(5).

Danke nochmals.
Zuletzt geändert von Re42 am 22.09.2022 17:33, insgesamt 2-mal geändert.
Benutzeravatar
NicTheQuick
Ein Admin
Beiträge: 8679
Registriert: 29.08.2004 20:20
Computerausstattung: Ryzen 7 5800X, 32 GB DDR4-3200
Ubuntu 22.04.3 LTS
GeForce RTX 3080 Ti
Wohnort: Saarbrücken
Kontaktdaten:

Re: Wie baut man einen Thread richtig auf?

Beitrag von NicTheQuick »

Der Code ist so immer noch nicht lauffähig, ohne das man da Fenster und alles mögliche drum herum baut.

Aber grundlegend hast du Threads entweder falsch verstanden oder du willst da etwas machen, wozu es gar keine Threads benötigt. In der Regel startet man Threads nicht zig mal um das selbe zu machen, sondern man startet einen Thread und der läuft eben einfach weiter. Ein Thread ist ein Programmteil, der neben dem Hauptprogramm läuft. Wenn du ihn immer wieder startest bevor der letzte Thread sich selbst beendet hat, hast du irgendwann ganz viele Threads gleichzeitig laufen. Und es sieht so aus, dass dein Thread immer mindestens 1100 ms läuft.

Innerhalb des Threads wertest du außerdem Events aus, bzw. um genauer zu sein nutzt du die Variable 'event', die sowieso immer 0 ist. Außer sie ist global, aber das kann man in deinem Code nicht sehen, weil er eben unvollständig ist. Aber auch 'EventMenu()' gehört da nicht.

Eine Bitte an dich: Beantworte uns mal die Frage, was genau du erreichen möchtest. Damit ist es viel einfacher zum Ziel zu kommen als von hinten durch die Brust ins Auge Threads zu erklären.
Bild
Re42
Beiträge: 91
Registriert: 08.11.2020 23:41

Re: Wie baut man einen Thread richtig auf?

Beitrag von Re42 »

Ich würde am liebsten gar keinen Thread laufen lassen müssen. Statt des Threads war da erst eine Procedure und die war auf jeden Fall vor jedem Neuaufruf auch wieder beendet.

Was ich erreichen will, ist, daß ich während des Abspielens von max. 20 Tönen hintereinander deren Lautstärke über ein ScrollBarGadhet regeln kann, ohne daß die Schleife stehen bleibt und damit dann auch das Abspielen der Töne. In einer For-Next-Schleife werden die Töne aus dem Array aufgerufen und die Abspiellänge der Töne wurde ursprünglich in einer Subroutine geregelt, um das nicht für jeden Ton extra schreiben zu müssen. Es gibt dann aber Probleme mit dem ScrollBarGadget, weil die Repeatschleife stehen bleibt, sobald ich da drauf klicke. Daher jetzt das Thema Thread.

Ich habe jetzt leider erstmal keine Zeit mehr. Ich melde mich später wieder. Danke.
Zuletzt geändert von Re42 am 23.09.2022 12:11, insgesamt 2-mal geändert.
Benutzeravatar
jacdelad
Beiträge: 348
Registriert: 03.02.2021 13:39
Computerausstattung: Ryzen 5800X, 108TB Festplatte, 32GB RAM, Radeon 7770OC
Wohnort: Riesa
Kontaktdaten:

Re: Wie baut man einen Thread richtig auf?

Beitrag von jacdelad »

Aber bitte mit Code und einer Beschreibung, was dein Ziel ist. Sonst bin ich raus.
PureBasic 6.04/XProfan X4a/Embarcadero RAD Studio 11/Perl 5.2/Python 3.10
Windows 11/Ryzen 5800X/32GB RAM/Radeon 7770 OC/3TB SSD/11TB HDD
Synology DS1821+/36GB RAM/130TB
Synology DS920+/20GB RAM/54TB
Synology DS916+ii/8GB RAM/12TB
Re42
Beiträge: 91
Registriert: 08.11.2020 23:41

Re: Wie baut man einen Thread richtig auf?

Beitrag von Re42 »

Ich habe jetzt mittlerweile mal einen lauffähigen Code zusammengestellt. Das Fenster ist zwar wesentlich kleiner als im Originalprogramm, aber es soll ja jetzt auch nur gezeigt werden, was prinzipiell passiert:

Über die Leertaste kann im Originalprogramm das Abspielen / Stoppen von Tönen ausgelöst werden. Das habe ich jetzt ersetzt durch Zahlen. Mir ist klar, dass ich mir in dem Fall Select - EndSelect auch hätte sparen können, aber beim Abspielen von Tönen geht das nicht anders, weil nicht einfach PlaySound(zahl) geschrieben werden kann, da muß jedesmal die jeweilige Zahl in der Klammer stehen.

Die Subroutine regelt die Abspiellänge mit Timer. Nicht mit Delay, damit über die Leertaste die Wiedergabe auch jederzeit wieder gestoppt werden kann.

Über das ScrollBarGadget kann im Originalprogramm die Lautstärke geregelt werden. Und jetzt das Problem dabei: Sobald das ScrollBarGadget angeklickt wird, bleibt die Repeat-Schleife in der Subroutine stehen. In der Praxis klingt dann der zuletzt wiedergegebene Ton aus und die Lautstärkeregelung ist so nicht gerade vom feinsten. Wie kann das beseitigt werden?

Euch wird auffallen, dass in der Subroutinen-Repeat-Schleife auch nochmal drin steht event = WaitWindowEvent(5) und auch nochmal ExamineKeyboard(). Die Abfrage in der Hauptschleife ist ja dann aber abgekapselt. Geht das ggf. auch anders? Das kann doch kein Geheimwissen sein, bitte erklärt mir, wie das ggf. besser geht. Gestern hatte ich auch mit Prozedur experimentiert, aber das war Murks, daher jetzt Subroutine.

Hier nun der Code:

Code: Alles auswählen

If InitSprite() = 0
  MessageRequester("InitSprite failed", "")
EndIf

If InitMouse() = 0
  MessageRequester("InitMouse failed","")
EndIf

If InitKeyboard()
  ;MessageRequester("InitKeyboard failed", "")
EndIf  
    
 If OpenWindow(1,0,0,130,413,"",#PB_Window_SystemMenu | #PB_Window_MinimizeGadget | #PB_Window_MaximizeGadget | #PB_Window_ScreenCentered) = 0 ; 412
   ;MessageRequester("OpenWindow failed", "")
 EndIf
 
 If OpenWindowedScreen(WindowID(1),0,0,110,413) = 0
   MessageRequester("OpenWindowedScreen failed", "")
 EndIf
 
   Procedure BindVScrollDatas()
     Shared ggst.d
     ggst.d = GetGadgetState(1)
     svl.d = 91 - ggst.d 
   EndProcedure
 
   ScrollBarGadget(1,110,25,20,363,1,100,10,#PB_ScrollBar_Vertical) ; 1,1010,19,20,375,1,100,10
   SetGadgetState(1,46)
   
   ggst.d = GetGadgetState(1)
   
   BindGadgetEvent(1, @BindVScrollDatas())
   
   Dim zahl.d(9)
   For i = 1 To 5
     zahl.d(i-1) = i
   Next
   
   Repeat
     event = WaitWindowEvent(5)
      Select event
        Case #PB_Event_LeftClick
        ;...
     EndSelect
     
     ExamineKeyboard()
     
     If KeyboardReleased(#PB_Key_Space) And space = 2
       space = 0
     EndIf
     
     If KeyboardPushed(#PB_Key_Space) And space = 0
       space = 1
       
       For i = 1 To 5
         zahl = zahl.d(i-1)
         
         Select zahl
           Case 1
             Debug zahl
             
             Gosub Spiellaenge
             If br = 1
               br = 0
               i = 5
               Break
             EndIf
           Case 2
               Debug zahl
               
             Gosub Spiellaenge
             If br = 1
               br = 0
               i = 5
               Break
             EndIf
           Case 3
             Debug zahl
             
             Gosub Spiellaenge
             If br = 1
               br = 0
               i = 5
               Break
             EndIf
           Case 4
             Debug zahl
             
             Gosub Spiellaenge
             If br = 1
               br = 0
               i = 5
               Break
             EndIf
           Case 5
             Debug zahl
             
             Gosub Spiellaenge
             If br = 1
               br = 0
               i = 5
               Break
             EndIf
         EndSelect
       Next
     EndIf
     
   Until event = #PB_Event_CloseWindow
   End
   
   Spiellaenge:
     starttime = ElapsedMilliseconds()
     
     Repeat
       event = WaitWindowEvent(5)
       
       ExamineKeyboard()
       
       time = ElapsedMilliseconds()
       
       If KeyboardReleased(#PB_Key_Space) And space = 1
         space = 0 
       EndIf
       
       If KeyboardPushed(#PB_Key_Space) And space = 0
         space = 2
         br = 1
         Break
       EndIf
       
       If KeyboardPushed(#PB_Key_Right) Or KeyboardPushed(#PB_Key_Up)  
         ggst.d = ggst.d - 0.3
           If ggst < 0
             ggst = 0
           EndIf
         SetGadgetState(1,ggst.d)
       EndIf
        
       If KeyboardPushed(#PB_Key_Left) Or KeyboardPushed(#PB_Key_Down)  
         ggst.d = ggst.d + 0.3
           If ggst > 91
             ggst = 91
           EndIf
         SetGadgetState(1,ggst.d)
       EndIf
       
     Until (time - starttime) > 1100
   Return
Danke für weitere Hilfe.
Antworten