HOW TO INTERRUPT A RUNNING PROCEDURE

Just starting out? Need help? Post your questions and find answers here.
ludoke
Enthusiast
Enthusiast
Posts: 153
Joined: Fri Jul 08, 2016 5:35 pm
Location: Essen (Belgium)

HOW TO INTERRUPT A RUNNING PROCEDURE

Post by ludoke »

;How to interrupt an running procedure ?

Code: Select all

Enumeration 
  #main_win: #font
  #F1  
  #main_menu
  #test1
  #test2
  #break
  #text
EndEnumeration  
;-------------------------------------------------------
Global win_color.l=$E1C193
Global breaking=0
;-------------------------------------------------------
Declare mainmenu()
Declare sneltoets()
Declare proces1()
Declare proces2()
Declare breaking()
;-------------------------------------------------------
  LoadFont(#font,"caladea",12, #PB_Font_Bold) 
flags=#PB_Window_SystemMenu;| #PB_Window_Maximize;#PB_Window3D_Borderless;|#PB_Window_ScreenCentered 
If OpenWindow (#main_win,200,200,500,500, "Break test" ,flags )
  SetWindowColor(#main_win,win_color)
  TextGadget(#text,100,300,300,30,"ok")
   sneltoets()   ;shortcut keys
   mainmenu()
 Repeat
    Ev = WaitWindowEvent()
    Select ev   ;
        Case #PB_Event_Menu                  
            Select  EventMenu()               
                Case #F1     ;break 
                     breaking=1
               EndSelect
        Case #PB_Event_Gadget    
            Select EventGadget()
                Case #test1    
                    breaking=0
                    proces1()
                    Debug "test1"                                
               Case #test2                   
                   breaking=0
                   proces2()
                   Debug "test2"
               Case #break
                  breaking=1
                  Debug "break"
              EndSelect  
    EndSelect
    Until ev=#PB_Event_CloseWindow 
EndIf
End   
;--------------------------------------------------------
Procedure breaking()
   TextGadget(#text,100,300,300,30,"interrupted")   
EndProcedure
;----------------------------------------------------------
Procedure proces1()
  n.l
  TextGadget(#text,100,300,300,30,"RUNNING1")
  For n=0 To 10000
    Delay (10)  ;
    If breaking=1  ;test if break is pressed
         Break
      EndIf
    Next  
    If breaking=0
      TextGadget(#text,100,300,300,30,"end1")
    Else
      breaking()
      EndIf
   EndProcedure
   ;--------------------------------------------------------------
   Procedure proces2()
     n.l
       TextGadget(#text,100,300,300,30,"RUNNING2")
  For n=0 To 10000
    Delay (10)  ;
     If breaking=1
         Break
       EndIf
     Next  
      If breaking=0
      TextGadget(#text,100,300,300,30,"end2")
    Else
      breaking()
      EndIf
   EndProcedure
  ;--------------------------------------------------------------
Procedure mainmenu() 
   ContainerGadget(#main_menu,10,10,200,200, #PB_Container_Raised)
    If LoadFont(0, "Arial", 12,#PB_Font_Bold)
      SetGadgetFont(#PB_Default, FontID(0))   ; Set the loaded Arial 16 font as new standard
    EndIf

   ; SetGadgetFont(#main_menu, FontID(#font))   ; Set the loaded Arial 16 font as new standard
   SetGadgetColor(#main_menu, #PB_Gadget_BackColor ,$9D7742)  
   ButtonGadget(#test1 ,20,20,120,40,"TEST1")
   ButtonGadget(#TEST2 ,20,70,120,40,"TEST2")
   ButtonGadget(#break  ,20,120,120,40,"BREAK")   
   
  CloseGadgetList()
EndProcedure 
;---------------------------------------------------------------------------------
Procedure sneltoets()  ;sneltoetsen voor keybord events
   AddKeyboardShortcut(#main_win,  #PB_Shortcut_F1,#F1)  
 EndProcedure
 ;----------------------------------------------------------
 
User avatar
Kirito
New User
New User
Posts: 5
Joined: Wed Jan 24, 2018 11:38 am

Re: HOW TO INTERRUPT A RUNNING PROCEDURE

Post by Kirito »

I think you want to work with threads here.
Threads are parts of your code that are running async along your main-code.

In your code it goes like this:
Image

breaking can not be called until proces1() or proces2() are finished.
With threads it would be like this:
Image


Take a look at this code:

Code: Select all

Procedure Thread(dummy) ;This is our procedure, we want to interrupt
  For x=0 To 1000       ;Note: We need one parameter (for calling it as thread)
    PrintN(Str(x))      ;Don't ask why, it's PB related... (Sometimes we need parameters for Threads)
    Delay(10)
  Next 
  PrintN("[Ready]")
EndProcedure 


OpenConsole("Interrupt Example")
thr = CreateThread(@Thread(), 0) ;Here we create a Thread from our procedure

While IsThread(thr) ;As long the thread is running
  Delay(5)
  If Inkey() = "q"  ;we ask if q was pressed
    KillThread(thr) ;[Yes?]: Interrupt our thread
  EndIf 
Wend 

PrintN("=============================")
PrintN("End - Press [Return]")
Input()
Hope this can help you, have a nice day :)
~ Lately, there are days I can’t even remember the other world.
ludoke
Enthusiast
Enthusiast
Posts: 153
Joined: Fri Jul 08, 2016 5:35 pm
Location: Essen (Belgium)

Re: HOW TO INTERRUPT A RUNNING PROCEDURE

Post by ludoke »

KillThread(thr) ,The pb manual says This is a very dangerous function, and should only be used rarely .
Is there no other way?


Is there a way to look for a keypress for example within the procedure?
In the old days was this possible .

In pB there is InitKeyboard() ,but that do not work with openwindow only with opensreen ?
User avatar
skywalk
Addict
Addict
Posts: 3999
Joined: Wed Dec 23, 2009 10:14 pm
Location: Boston, MA

Re: HOW TO INTERRUPT A RUNNING PROCEDURE

Post by skywalk »

Yeah, KillThread() is a LAST resort.
Instead have a global structure or array or whatever, that both your main process and threads can query.
Then if your main process(gui) decides to stop threadx, threadx will stop the next time it looks at the shared variable.
So, this means each of your threads have to look at a "what do I do now" variable often.
With this, you can also pause and resume your threads.
Look to thread examples on the forum like this and others.
The nice thing about standards is there are so many to choose from. ~ Andrew Tanenbaum
infratec
Always Here
Always Here
Posts: 6874
Joined: Sun Sep 07, 2008 12:45 pm
Location: Germany

Re: HOW TO INTERRUPT A RUNNING PROCEDURE

Post by infratec »

http://www.purebasic.fr/english/viewtop ... 3&p=482048

scroll down to my thread example.
There you can see how to pass data to a thread and also exit the thread without kill.

Bernd
ludoke
Enthusiast
Enthusiast
Posts: 153
Joined: Fri Jul 08, 2016 5:35 pm
Location: Essen (Belgium)

Re: HOW TO INTERRUPT A RUNNING PROCEDURE

Post by ludoke »

thanks for your help,but it seems to difficult for me,I am not a expert in programming.
I thought windows responded to each interrupt, but that is not
For a friend ,I want to make a program for measure and drawing radiotube curves.
Because it work with an arduino ,the arduino receive commands from the pc and the arduino
answer with some measurement results.
But I can push a button on the arduino for generate a break condition in the procedure,I will try that.
Or I can rewrite the program with using openscreen() and keyboard().
Why is reading the keyboard possible with openscreen() and not with openwindow()?
infratec
Always Here
Always Here
Posts: 6874
Joined: Sun Sep 07, 2008 12:45 pm
Location: Germany

Re: HOW TO INTERRUPT A RUNNING PROCEDURE

Post by infratec »

In a window program you have normally something where the keyboard data is inserted when it is active.
Like a StringGadget() or EditorGadget().

You can use AddKeyboardShortcut() to catch something, but this key is than not longer inserted in a Gadget.

Or you can use window API : GetAsyncKeyState_() if you bought PB :wink:

http://www.purebasic.fr/english/viewtop ... 13&t=66288

Bernd
ludoke
Enthusiast
Enthusiast
Posts: 153
Joined: Fri Jul 08, 2016 5:35 pm
Location: Essen (Belgium)

Re: HOW TO INTERRUPT A RUNNING PROCEDURE

Post by ludoke »

yes I bought PB,
I put it here and it works !!!

thanks very mutch

Code: Select all

Procedure proces1()
  n.l
  TextGadget(#text,100,300,300,30,"RUNNING1")
  For n=0 To 1000
    Delay (10)  ;    
; ------------------------place here GetAsyncKeyState--------------------------------------------
             If GetAsyncKeyState_(#VK_F1)  ;
                 MessageRequester("Information", "stop", #PB_MessageRequester_Ok)
                  breaking=1              
              EndIf
;-----------------------------------------------It works -----------------------------------------
    If breaking=1 
         Break
      EndIf
    Next  
    If breaking=0
      TextGadget(#text,100,300,300,30,"end1")
    Else
      breaking()
      EndIf
   EndProcedure
Dude
Addict
Addict
Posts: 1907
Joined: Mon Feb 16, 2015 2:49 pm

Re: HOW TO INTERRUPT A RUNNING PROCEDURE

Post by Dude »

skywalk wrote:KillThread() is a LAST resort.
Agreed, but sometimes it's literally the only resort.
skywalk wrote:each of your threads have to look at a "what do I do now" variable often.
This is impossible for some situations (it can't look while a MessageRequester is being shown), or totally impractical due to the slowness this can cause (constantly looking during a big loop).

MSDN says this of terminating threads:
https://msdn.microsoft.com/en-us/library/windows/desktop/ms686717(v=vs.85).aspx wrote:You should call TerminateThread only if you know exactly what the target thread is doing, and you control all of the code that the target thread could possibly be running at the time of the termination. For example, TerminateThread can result in the following problems:
* If the target thread owns a critical section, the critical section will not be released.
* If the target thread is allocating memory from the heap, the heap lock will not be released.
* If the target thread is executing certain kernel32 calls when it is terminated, the kernel32 state for the thread's process could be inconsistent.
* If the target thread is manipulating the global state of a shared DLL, the state of the DLL could be destroyed, affecting other users of the DLL.
User avatar
skywalk
Addict
Addict
Posts: 3999
Joined: Wed Dec 23, 2009 10:14 pm
Location: Boston, MA

Re: HOW TO INTERRUPT A RUNNING PROCEDURE

Post by skywalk »

Dude wrote:
skywalk wrote:KillThread() is a LAST resort.
Agreed, but sometimes it's literally the only resort.
skywalk wrote:each of your threads have to look at a "what do I do now" variable often.
This is impossible for some situations (it can't look while a MessageRequester is being shown), or totally impractical due to the slowness this can cause (constantly looking during a big loop).
Why would a gui requestor affect your threads? If your thread pops a requestor, then it is by design, paused. The few clock cycles to check a global flag are well worth the ability to pause/resume/stop your threads gracefully. And your MS quote on terminate thread demands never using it. :wink:
The nice thing about standards is there are so many to choose from. ~ Andrew Tanenbaum
User avatar
J. Baker
Addict
Addict
Posts: 2178
Joined: Sun Apr 27, 2003 8:12 am
Location: USA
Contact:

Re: HOW TO INTERRUPT A RUNNING PROCEDURE

Post by J. Baker »

This is a simple way. You should easily figure out how to incorporate it. ;)

EDIT: Just noticed there is a PauseThread(Thread) described in the manual.

Code: Select all

Global Kill = 0

Procedure YourProcedure(null)
  Repeat
    If Kill = 0
      Debug "Thread Running"
    EndIf
      Delay(1)
  ForEver
EndProcedure

If OpenWindow(0, 100, 200, 220, 200, "Pause Thread", #PB_Window_SystemMenu | #PB_Window_MinimizeGadget)
 
  ButtonGadget  (1, 10, 10, 200, 20, "Pause Thread")
  ButtonGadget  (2, 10, 40, 200, 20, "Start Thread")
  DisableGadget(2, 1)
  
  CreateThread(@YourProcedure(), 0)
 
  Repeat
    Event = WaitWindowEvent()

    Select Event
     
       Case #PB_Event_Gadget
         Select EventGadget()
           Case 1 : Kill = 1 : Debug "Thread Paused" : DisableGadget(1, 1) : : DisableGadget(2, 0)
           Case 2 : Kill = 0 : DisableGadget(1, 0) : : DisableGadget(2, 1)
         EndSelect
     
     EndSelect

  Until Event = #PB_Event_CloseWindow
 
EndIf

End
Last edited by J. Baker on Fri Feb 16, 2018 9:54 pm, edited 2 times in total.
www.posemotion.com

PureBasic Tools for OS X: PureMonitor, plist Tool, Data Maker & App Chef

Mac: 10.13.6 / 1.4GHz Core 2 Duo / 2GB DDR3 / Nvidia 320M
PC: Win 7 / AMD 64 4000+ / 3GB DDR / Nvidia 720GT


Even the vine knows it surroundings but the man with eyes does not.
User avatar
mk-soft
Always Here
Always Here
Posts: 5406
Joined: Fri May 12, 2006 6:51 pm
Location: Germany

Re: HOW TO INTERRUPT A RUNNING PROCEDURE

Post by mk-soft »

I work alway with structure for Threads

Code: Select all

; Simple Thread

Structure udtWork
  ; Header
  ThreadID.i
  Exit.i
  ; Control
  Cmd.i
  State.i
  ; Data
  iVal1.i
  iVal2.i
EndStructure


Procedure thWork(*Work.udtWork)
  
  With *Work
    ; Startup
    Debug "Startup"
    \State = 1
    Delay(100)
    
    ; Loop
    Debug "Loop..."
    \State = 2
    Repeat
      Select \Cmd
        Case 1
          \State = 101
          Debug "Thread command 1"
          \iVal1 + 1
          Delay (1000)
          \State = 102
          \Cmd = 0
        Case 2
          \State = 201
          Debug "Thread command 2"
          \iVal2 + 1
          Delay (1000)
          \State = 202
          \Cmd = 0
        Default
          ; Cycle
          Debug "Thread cycle code"
          Delay(100)
      EndSelect
    Until \Exit
    
    ; Shutdown
    \State = 3
    Debug "Shutdown"
    Delay(2000)
    ; Exit
    \State = 4
    \Exit = 0
  EndWith
  
EndProcedure

; Test

Global MyWork.udtWork

MyWork\ThreadID = CreateThread(@thWork(), MyWork)
If MyWork\ThreadID
  With MyWork
    Delay(500)
    \Cmd = 1
    While \Cmd : Delay(500) : Wend
    \Cmd = 2
    While \Cmd : Delay(500) : Wend
    \Cmd = 1
    While \Cmd : Delay(500) : Wend
    \Cmd = 2
    While \Cmd : Delay(500) : Wend
    \Exit = 1
    While \Exit
      cnt + 1
      If cnt > 30
        KillThread(\ThreadID)
        Break
      EndIf
      Delay(100)
    Wend
    Debug "iVal1 = " + \iVal1
    Debug "iVal2 = " + \iVal2
    
  EndWith
  
EndIf
My Projects ThreadToGUI / OOP-BaseClass / EventDesigner V3
PB v3.30 / v5.75 - OS Mac Mini OSX 10.xx - VM Window Pro / Linux Ubuntu
Downloads on my Webspace / OneDrive
ludoke
Enthusiast
Enthusiast
Posts: 153
Joined: Fri Jul 08, 2016 5:35 pm
Location: Essen (Belgium)

Re: HOW TO INTERRUPT A RUNNING PROCEDURE

Post by ludoke »

all that you describe goes far above my knowledge, with a simple GetAsyncKeyState_(#VK_ESCAPE) does the job,it works but I do not know of this the wright way?

Code: Select all

procedure doSomeThing()
   for n=0 to 5000
     If GetAsyncKeyState_(#VK_ESCAPE)   
              interrupted =1               
                 Goto einde     ;also with break 
             EndIf 
    next
einde:
         ;but here is a new problem!!!
  MessageRequester("Information","interrupted !", #PB_MessageRequester_Ok)  
endprocedure
;------------------------------------------------------------
the problem:The requester is not shown

The program goes back to the eventloop ,even if I put the requester there it is not show,
but I do it on my own simple way ,I put this code in the eventloop and it works!
this code->
If interrupted=1
SetGadgetText(#break,"ONDERBROKEN!!")
interrupted=0
EndIf
Dude
Addict
Addict
Posts: 1907
Joined: Mon Feb 16, 2015 2:49 pm

Re: HOW TO INTERRUPT A RUNNING PROCEDURE

Post by Dude »

skywalk wrote:If your thread pops a requestor, then it is by design, paused.
Yes, but a paused thread is not an ended thread. ;)

I have a need to end a thread now, no matter what it's doing, and it's usually by a remote and/or timed command. When the user is away from the PC, any requesters that the thread showed (such as MessageBox, InputRequester, or OpenFileRequester) will just sit there instead, not letting the thread be ended; thus wasting valuable time and resources until the user comes back and manually acknowledge it. Not good at all.

Trust me, if I could end a thread cleanly and immediately, no matter what it's doing or showing at the time, I would.

Maybe all the PureBasic requesters need some sort of "auto-cancel" callback ability added to them?
User avatar
mk-soft
Always Here
Always Here
Posts: 5406
Joined: Fri May 12, 2006 6:51 pm
Location: Germany

Re: HOW TO INTERRUPT A RUNNING PROCEDURE

Post by mk-soft »

The MessageBox, etc. are managed by the OS and they are always waiting for an operator instruction.

If you want to abort these you have to build your own requester.

Besides, it's not good to open it from the thread.
I recommend that you write your own requester and open it via a PostEvent and then continue the thread after input with Semaphore, or close the thread after timeout to close your own requester.


Translated with www.DeepL.com/Translator
My Projects ThreadToGUI / OOP-BaseClass / EventDesigner V3
PB v3.30 / v5.75 - OS Mac Mini OSX 10.xx - VM Window Pro / Linux Ubuntu
Downloads on my Webspace / OneDrive
Post Reply