Page 1 of 1

Simple Thread Control

Posted: Sun Nov 22, 2015 3:57 pm
by mk-soft
It is sometimes asked how to control threads.
I have times a simple example created without special imported functions.

Maybe hate anyone more simple examples for beginners.

Update v1.03
- Update example with Semaphore

Code: Select all

;-TOP

; Comment:  Simple Thread Control 
; Author:   mk-soft
; Version:  v1.03
; Create:   22.11.2015
; Update:   01.09.2016

Enumeration 
  #thread_cmd_nothing
  #thread_cmd_start
  #thread_cmd_pause
  #thread_cmd_continue
  #thread_cmd_stop
EndEnumeration

Enumeration
  #thread_state_nothing
  #thread_state_startingup
  #thread_state_running
  #thread_state_pausing
  #thread_state_paused
  #thread_state_continued
  #thread_state_stopping
  #thread_state_stopped
  #thread_state_finished
EndEnumeration

Enumeration #PB_Event_FirstCustomValue
  #thread_event_state
EndEnumeration

Structure udtMyThread
  ; Header
  id.i
  signal.i
  cmd.i
  state.i
  ; Userdata
  counter.i
EndStructure

; ***************************************************************************************

Procedure ThreadState()
  
  Protected *this.udtMyThread
  
  *this = EventGadget()
  
  Select EventType()
    Case #thread_state_nothing
      StatusBarText(0, 0, "Nothing")
      
    Case #thread_state_startingup
      StatusBarText(0, 0, "Startingup")
      
    Case #thread_state_running
      StatusBarText(0, 0, "Running")
      
    Case #thread_state_pausing
      StatusBarText(0, 0, "Pause pending")
      
    Case #thread_state_paused
      StatusBarText(0, 0, "Paused")
      
    Case #thread_state_continued
      StatusBarText(0, 0, "Continued")
      
    Case #thread_state_stopping
      StatusBarText(0, 0, "Stopping")
      
    Case #thread_state_stopped
      StatusBarText(0, 0, "Stopped")
      
    Case #thread_state_finished
      StatusBarText(0, 0, "Finished")
      
  EndSelect
  
EndProcedure

Macro SendThreadState(This, State)
  PostEvent(#thread_event_state, 0, This, State)
EndMacro

; ***************************************************************************************

; Thread control macros

Macro MyStartThread(thread)
  If Not IsThread(thread\id)
    thread\id = CreateThread(@MyThread(), @thread1)
  EndIf
  thread\cmd = #thread_cmd_start
  If thread\signal
    SignalSemaphore(thread\signal)
  EndIf
EndMacro

Macro MyPauseThread(thread)
  thread\cmd = #thread_cmd_pause
EndMacro

Macro MyContinueThread(thread)
  thread\cmd = #thread_cmd_continue
  If thread\signal
    SignalSemaphore(thread\signal)
  EndIf
EndMacro

Macro MyStopThread(thread)
  thread\cmd = #thread_cmd_stop
  If thread\signal
    SignalSemaphore(thread\signal)
  EndIf
EndMacro

; ***************************************************************************************

Procedure MyThread(*this.udtMyThread)
  
  Debug "Created Thread"
  
  With *this
    \signal = CreateSemaphore(1)
    
    Repeat
      Select \cmd 
        Case #thread_cmd_start
          \cmd = #thread_cmd_nothing
          If \state <= #thread_state_nothing Or \state >= #thread_state_finished
            \state = #thread_state_startingup
            SendThreadState(*this, \state)
            ;TODO Init thread
            Debug "Init Thread"
            Delay(2000)
            
            \state = #thread_state_running
            SendThreadState(*this, \state)
            
          EndIf
          
        Case #thread_cmd_pause
          \cmd = #thread_cmd_nothing
          If \state = #thread_state_running
            \state = #thread_state_pausing
            SendThreadState(*this, \state)
            ;TODO Pausing thread
            Debug "Paused Thread"
            Delay(2000)
            
            \state = #thread_state_paused
            SendThreadState(*this, \state)
            
          EndIf
          
        Case #thread_cmd_continue
          \cmd = #thread_cmd_nothing
          If \state = #thread_state_paused
            \state = #thread_state_continued
            SendThreadState(*this, \state)
            ;TODO Continue thread
            Debug "Continue Thread"
            Delay(2000)
            
            \state = #thread_state_running
            SendThreadState(*this, \state)
            
          EndIf
          
        Case #thread_cmd_stop
          \cmd = #thread_cmd_nothing
          If \state < #thread_state_stopping
            \state = #thread_state_stopping
            SendThreadState(*this, \state)
            ;TODO Stopping thread
            Debug "Stopping Thread"
            Delay(2000)
            
            \state = #thread_state_stopped
            SendThreadState(*this, \state)
            
          EndIf
          
      EndSelect
      
      Select \state
        Case #thread_state_running
          ;TODO Cycle programm
          Debug "Thread running " + \counter
          
          \counter + 1
          Delay(1000)
          
        Case #thread_state_nothing, #thread_state_paused   
          WaitSemaphore(\signal)
          
        Default
          Delay(100)
          
      EndSelect
      
    Until \state = #thread_state_stopped
    
    Debug "Release Thread"
    
    \state = #thread_state_finished
    SendThreadState(*this, \state)
    
    ; Release thread
    FreeSemaphore(\signal)
    \signal = 0
    \id = 0
  EndWith
  
EndProcedure

; ***************************************************************************************

CompilerIf #PB_Compiler_IsMainFile
  
  Global thread1.udtMyThread
  
  Procedure Main()
    
    If OpenWindow(0, #PB_Any, #PB_Any, 530, 60, "Simple Thread Control")
      CreateStatusBar(0, WindowID(0))
      AddStatusBarField(1000)
      ButtonGadget(0, 10, 10, 120, 25, "Start")
      ButtonGadget(1, 140, 10, 120, 25, "Pause")
      ButtonGadget(2, 270, 10, 120, 25, "Continue")
      ButtonGadget(3, 400, 10, 120, 25, "Stop")
      
      BindEvent(#thread_event_state, @ThreadState())
      
      ; We can create thread without start processing
      thread1\id = CreateThread(@MyThread(), @thread1)
      
      Repeat
        Select WaitWindowEvent()
          Case #PB_Event_Gadget  
            Select EventGadget()
              Case 0
                MyStartThread(thread1)
                
              Case 1
                MyPauseThread(thread1)
                
              Case 2
                MyContinueThread(thread1)
                
              Case 3
                MyStopThread(thread1)
                
            EndSelect
            
          Case #PB_Event_CloseWindow
            Break
            
        EndSelect
        
      ForEver
      
    EndIf
    
  EndProcedure : Main()
  
  
CompilerEndIf

Re: Simple Thread Control

Posted: Mon Nov 23, 2015 11:01 am
by Kwai chang caine
Code very usefull, for understanding the thread
Works great, thanks a lot for sharing 8)

Re: Simple Thread Control

Posted: Mon Nov 23, 2015 9:31 pm
by davido
@mk-soft,
Nice, instructive, example.
Thank you for sharing. :D

Re: Simple Thread Control

Posted: Fri Sep 02, 2016 4:13 pm
by mk-soft
Update v1.03
- Update example with Semaphore

Have just a little much time, and I expanded the example with use of semaphore :wink:

Re: Simple Thread Control

Posted: Sat Sep 03, 2016 3:37 pm
by aaaaaaaargh
Thanks for sharing!