Thread-Pool - Das angegebene 'Thread' ist null

Anfängerfragen zum Programmieren mit PureBasic.
Benutzeravatar
mk-soft
Beiträge: 3855
Registriert: 24.11.2004 13:12
Wohnort: Germany

Re: Thread-Pool - Das angegebene 'Thread' ist null

Beitrag von mk-soft »

MessageRequester aus einem Thread zu starten führt auch zu Problemen.
Um aus den Thread eine Userabfrage auszuführen habe ich hier ein SendEvent(...)

http://www.purebasic.fr/german/viewtopi ... =sendevent
Alles ist möglich, fragt sich nur wie...
Projekte ThreadToGUI / EventDesigner V3 / OOP-BaseClass-Modul
Downloads auf MyWebspace / OneDrive
Benutzeravatar
uweb
Beiträge: 461
Registriert: 13.07.2005 08:39

Re: Thread-Pool - Das angegebene 'Thread' ist null

Beitrag von uweb »

Danke!
Ja, das habe ich übersehen.

Danke auch für SendEvent().
Das sieht gut aus.
Da ich aber ohnehin schon PostEvent() verwende und der MessageRequester nur zum Testen da ist reicht das zumindest im Moment.

Wahrscheinlich kommen noch einige andere Themen auf mich zu sobald ich die Threads dann in einen Server einbauen will.

Ich war gerade dabei das ganze noch einmal mit echter Verarbeitung (statt #SleepTime) zu testen.
Dadurch konnte ich die Zeiten ohne Thread auch nicht mehr einfach nur vorhersagen.
Deswegen habe ich zum Testen noch ProzedurC() geschrieben.

Es ist schon erstaunlich was beim Herumspielen mit #ThreadQuantity und #JobQuantity heraus kommt.

Code: Alles auswählen

;-TOP
;CompilerIf #PB_Compiler_Thread

DisableDebugger

EnableExplicit

Global idThread.l, dwExitCode.l, x, TextGadgetText.s
Global StartTimeA, StartTimeB, StartTimeC, ElapsedTimeA, ElapsedTimeB, ElapsedTimeC
Define i, Event, Quit

; #ThreadQuantity = 64
; #JobQuantity = 256

#ThreadQuantity = 256
#JobQuantity = 1024

; #ThreadQuantity = 16
; #JobQuantity = 1024

; #ThreadQuantity = 16
; #JobQuantity = 1024

Enumeration #PB_Event_FirstCustomValue
  #TestReady
  #ThreadReady
  #NewText
EndEnumeration

Global Dim ThreadHandles(#ThreadQuantity-1)

Macro Work
  For i = 1 To 10
    ys = Str(x*i)
    ys = MD5Fingerprint(@ys, StringByteLength(ys))
    ys = UCase(ys) 
    ys = MD5Fingerprint(@ys, StringByteLength(ys))
    ys = LCase(ys)
    ys = MD5Fingerprint(@ys, StringByteLength(ys))
    Debug ys
  Next
EndMacro


Procedure ThreadA()
  Protected ys.s, yq.q, i
  Repeat 
    Work ; Arbeitszeit generieren um die Threads gleichmäßig auszulasten - läuft auch ohne stabil
    PostEvent(#ThreadReady)
    SuspendThread_(GetCurrentThread_()) 
  ForEver 
EndProcedure 

Procedure ThreadB() 
  Protected ys.s, yq.q, i
  Work
  PostEvent(#ThreadReady)
EndProcedure 

Procedure ProzedurC() 
  Protected ys.s, yq.q, i
  Work
  x+1
  ;PostEvent(#ThreadReady) ist hier nicht nötig, da klar ist wann die Verarbeitung beendet ist
EndProcedure 


Procedure Test() 
  Protected i, j
  
  ;- TestB
  ;Das sequentielle CreateThread_() wird als erstes getestet um sicher zu sein, dass keine Altlasten bremsen.
  x = 0
  TextGadgetText = "Teste sequentielles CreateThread_()"
  PostEvent(#NewText)
  Delay(100)
  StartTimeB = ElapsedMilliseconds()
  For i = 1 To #JobQuantity
    Debug "B Job : "+Str(i)
    CreateThread_(0, 0, @ThreadB(), 0, 0, @idThread)
  Next i
  Repeat: Until x = #JobQuantity
  ElapsedTimeB = ElapsedMilliseconds()-StartTimeB
  
  
  ;- TestA  
  x = 0
  TextGadgetText = "Teste vorbereitete Threads"
  PostEvent(#NewText)
  Delay(100)
  StartTimeA = ElapsedMilliseconds()
  For i = 1 To #JobQuantity
    Debug "A Job : "+Str(i)
    Repeat     
      For j = 0 To #ThreadQuantity-1
        If ResumeThread_(ThreadHandles(j)) >0 : Break 2 : EndIf
      Next j
    ForEver
  Next i
  Repeat: Until x = #JobQuantity
  ElapsedTimeA = ElapsedMilliseconds()-StartTimeA
  
  ;   For j = 0 To #ThreadQuantity-1
  ;     Repeat: Until TerminateThread_(ThreadHandles(j),@dwExitCode)
  ;   Next j
  
  
  ;- TestC
  x = 0
  TextGadgetText = "Teste sequentiellen Aufruf von ProzedurC()"
  PostEvent(#NewText)
  Delay(100)
  
  StartTimeC = ElapsedMilliseconds()
  For i = 1 To #JobQuantity
    Debug "C Job : "+Str(i)
    ProzedurC()
  Next i
  Repeat: Until x = #JobQuantity
  ElapsedTimeC = ElapsedMilliseconds()-StartTimeC
  
  TextGadgetText = "Fertig!"
  PostEvent(#NewText)
  PostEvent(#TestReady)
  
EndProcedure 


If OpenWindow(0, 100, 200, 200, 50, "Please wait")
  TextGadget(1, 0,  20, 200, 30, "Vorbereitung ...", #PB_Text_Center)
  
  For i = 0 To #ThreadQuantity-1 ; Threads vorbereiten
    ThreadHandles(i) = CreateThread_(0, 0, @ThreadA(), 0, #CREATE_SUSPENDED, @idThread) 
    ; #CREATE_SUSPENDED -> "Threads werden erzeugt - arbeiten aber noch nicht"
  Next i 
  
  For i = 0 To #ThreadQuantity-1 ; überprüfen ob alle Threads startbereit sind
    If ThreadHandles(i)
      Repeat : Until SuspendThread_(ThreadHandles(i)) >0
      ResumeThread_(ThreadHandles(i)) ; Suspend-Wert zurück setzen
    EndIf
  Next i
  
  CreateThread_(0, 0, @Test(), 0, 0, @idThread)
  
  Repeat
    Event = WaitWindowEvent()
    Select Event
      Case #PB_Event_CloseWindow
        Quit = 1
      Case #ThreadReady
        x+1
      Case #TestReady
        If MessageRequester("Vorbereitete Threads gegenüber einfachem CreateThread_() gegenüber Aufruf von ProzedurC()", Str(ElapsedTimeA)+" zu "+Str(ElapsedTimeB)+" zu "+Str(ElapsedTimeC), #PB_MessageRequester_Ok)
          Quit = 1
        EndIf
      Case #NewText
        SetGadgetText(1, TextGadgetText)
    EndSelect
  Until Quit = 1
EndIf

; CompilerElse
;   Debug "Bitte 'Thread-sicheren Exekutable erstellen' in den Compiler-Optionen auswählen." 
; CompilerEndIf
Antworten