HOW TO INTERRUPT A RUNNING PROCEDURE

Just starting out? Need help? Post your questions and find answers here.
User avatar
mk-soft
Always Here
Always Here
Posts: 5401
Joined: Fri May 12, 2006 6:51 pm
Location: Germany

Re: HOW TO INTERRUPT A RUNNING PROCEDURE

Post by mk-soft »

Ok,

Here now an example with...
- Helpfunction SendEvent(...)
- MessageRequester with Timeout
- Thread with open MessageRequester

Works with all OS, because all Windows and Gadgets functions call inside Mainscope

Code: Select all

;-TOP

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

;-Begin Of SendEvent

; Comment : SendEvent
; Author  : mk-soft
; Version : v1.06
; Create  : unknown
; Update  : 07.08.2016

;- Structure
Structure udtSendEvent
  Signal.i
  Result.i
  *pData
EndStructure

; ---------------------------------------------------------------------------------------

Procedure SendEvent(Event, Window = 0, Object = 0, EventType = 0, pData = 0, Semaphore = 0)
  
  Protected MyEvent.udtSendEvent, result
  
  With MyEvent
    If Semaphore
      \Signal = Semaphore
    Else
      \Signal = CreateSemaphore()
    EndIf
    \pData = pData
    PostEvent(Event, Window, Object, EventType, @MyEvent)
    WaitSemaphore(\Signal)
    result = \Result
    If Semaphore = 0
      FreeSemaphore(\Signal)
    EndIf
  EndWith
  
  ProcedureReturn result
  
EndProcedure

; ---------------------------------------------------------------------------------------

Procedure SendEventData(*MyEvent.udtSendEvent)
  ProcedureReturn *MyEvent\pData
EndProcedure

; ---------------------------------------------------------------------------------------

Procedure DispatchEvent(*MyEvent.udtSendEvent, result)
  *MyEvent\Result = result
  SignalSemaphore(*MyEvent\Signal)
EndProcedure

;- End Of SendEvent

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

;- Example

CompilerIf #PB_Compiler_IsMainFile
  
  EnableExplicit
  
  ; ***************************************************************************************
  
  Procedure MyMessageRequester(Parent, Title.s, Text.s, Flags=#PB_MessageRequester_Ok, Timeout=0)
    Protected Result, Dialog, Info, Button1, Button2, Button3, Time
    Dialog = OpenWindow(#PB_Any, 0, 0, 500, 100, Title, #PB_Window_WindowCentered, Parent)
    If Dialog
      DisableWindow(Parent, 1)
      StickyWindow(Dialog, #True)
      TextGadget(#PB_Any, 10, 10, 480, 50, Text, #PB_Text_Center)
      Select Flags
        Case #PB_MessageRequester_Ok
          Button1 = ButtonGadget(#PB_Any, 200, 70, 100, 25, "Ok")
        Case #PB_MessageRequester_YesNo
          Button1 = ButtonGadget(#PB_Any, 150, 70, 100, 25, "Yes")
          Button2 = ButtonGadget(#PB_Any, 260, 70,100, 25, "No")
        Case #PB_MessageRequester_YesNoCancel
          Button1 = ButtonGadget(#PB_Any, 90, 70, 100, 25, "Yes")
          Button2 = ButtonGadget(#PB_Any, 200, 70, 100, 25, "No")
          Button3 = ButtonGadget(#PB_Any, 310, 70, 100, 25, "Cancel")
      EndSelect
      If Timeout
        Time = ElapsedMilliseconds()
      EndIf
      Repeat
        Select WaitWindowEvent(100)
          Case #PB_Event_Gadget
            Select EventGadget()
              Case Button1
                Result = #PB_MessageRequester_Yes
                Break
              Case Button2
                Result = #PB_MessageRequester_No
                Break
              Case Button3
                Result = #PB_MessageRequester_Cancel
                Break
            EndSelect
          Default
            If Timeout
              If ElapsedMilliseconds() - Time > Timeout
                Result = -1
                Break
              EndIf
            EndIf
        EndSelect
      ForEver
      DisableWindow(Parent, 0)
      CloseWindow(Dialog)
      ProcedureReturn Result
    EndIf
  EndProcedure
  
  ;- Memory string helper
  
  Procedure AllocateString(String.s)
    Protected *mem.string
    *mem = AllocateStructure(string)
    If *mem
      *mem\s = String
    EndIf
    ProcedureReturn *mem
  EndProcedure
  
  ; ---------------------------------------------------------------------------------------
  
  Procedure.s FreeString(*mem.string)
    Protected result.s
    If *mem
      result = *mem\s
      FreeStructure(*mem)
    EndIf
    ProcedureReturn result
  EndProcedure
  
  ; ***************************************************************************************

  Enumeration
    #Window
  EndEnumeration
  
  ;- Constants
  Enumeration #PB_Event_FirstCustomValue
    #My_Event_Messagebox
    #My_Event_Inputbox
  EndEnumeration
  
  Procedure Thread1(Null)
    
    Debug "Init Thread 1"
    Protected result
    
    Repeat
      Delay(500)
      result = SendEvent(#My_Event_Messagebox, 0, 0, 0, Random(100))
      Select result
        Case #PB_MessageRequester_Yes
          Debug "#PB_MessageRequester_Yes"
        Case #PB_MessageRequester_No
          Debug "#PB_MessageRequester_No"
        Case #PB_MessageRequester_Cancel
          Debug "#PB_MessageRequester_Cancel"
        Case -1
          Debug "MessageRequester Timeout"
      EndSelect
    Until result = #PB_MessageRequester_Cancel Or result = -1
    
    Debug "Exit Thread 1"
    
  EndProcedure
  
  Procedure Main()
    Protected exit, th1, th2
    Protected MyEvent, value, result, text.s 
    
    If OpenWindow(#Window, 0, 0, 800, 600, "WindowTitle", #PB_Window_MinimizeGadget|#PB_Window_ScreenCentered)
      th1 = CreateThread(@Thread1(), #Null)
      Repeat
        Select WaitWindowEvent()
          Case #PB_Event_CloseWindow
            Break
            
          Case #PB_Event_Gadget
            
          Case #My_Event_Messagebox
            MyEvent = EventData()
            value = SendEventData(MyEvent)
            result = MyMessageRequester(#Window, "Thread 1", "What happens next? (Timeout: 20000ms)" + #LF$ + "(Code " + value + ")", #PB_MessageRequester_YesNoCancel, 20000)
            DispatchEvent(MyEvent, result)
        EndSelect
      ForEver
      
      If IsThread(th1)
        KillThread(th1)
      EndIf
      If IsThread(th2)
        KillThread(th2)
      EndIf
      
    EndIf
  EndProcedure : Main()
  
CompilerEndIf
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
Dude
Addict
Addict
Posts: 1907
Joined: Mon Feb 16, 2015 2:49 pm

Re: HOW TO INTERRUPT A RUNNING PROCEDURE

Post by Dude »

@mk-soft, is that example meant for me? Because it uses KillThread(), which we're trying to avoid? And it doesn't take into account any other requesters, like OpenFileRequester(), InputRequester(), ColorRequester(), etc.
User avatar
mk-soft
Always Here
Always Here
Posts: 5401
Joined: Fri May 12, 2006 6:51 pm
Location: Germany

Re: HOW TO INTERRUPT A RUNNING PROCEDURE

Post by mk-soft »

The kill thread is from an old example. Sorry,

Of course you have to build the other dialogues yourself.
It's just an example how to close a thread with dialog after a timeout. You can also include the timeout Global in your own requester.

If it's windows and the ClassName of the requester knows, you can send a #WM_CLOSE or something like this
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 »

Hello ,i am still having problems to interrupt a procedure.
For the moment I use
If GetAsyncKeyState_(#VK_F1) ;
MessageRequester("Information", "stop", #PB_MessageRequester_Ok)
breaking=1
EndIf
In my early code I have 3 buttons ,if I start with a button1 press,I can interrupt the procedure,but when
I press p.e. button 2 while the procedure proces1 is running the program crash.
AddKeyboardShortcut... can not interrupt a running procedure
Are threads the only solution,or must i use using OpenScreen() and initkeyboard()
infratec
Always Here
Always Here
Posts: 6873
Joined: Sun Sep 07, 2008 12:45 pm
Location: Germany

Re: HOW TO INTERRUPT A RUNNING PROCEDURE

Post by infratec »

Hi,

you have to understand how a program with windows works.

Everything is event driven.

You have one point in your code where the events are processed.
If you can not reach this point, nothing can happens.
If you want todo something beside which have to run always, you should use threads.
Else you block something.

And if you go away from a window program you still have the same problem.
Or you have to check always all events in every loop which you code.

Bernd
User avatar
skywalk
Addict
Addict
Posts: 3997
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: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?
I agree that PB threads should not create their own windows, but a MessageRequester is a system call. I use them for convenience and therefore do not attempt to kill the thread that issued the requester. If your app requires that control, then do as mk-soft/infratec suggest in their examples. Your threads must ping-pong with the main event loop through Thread[PostEvent()-WaitSemaphore()] --> Main[BindEvent(@myEvent())-SignalSemaphore()]. I have also tinkered with timed MessageRequesters, but they have fallen away due to lack of use. I want the issues that trigger MessageRequester's solved or logged.
The nice thing about standards is there are so many to choose from. ~ Andrew Tanenbaum
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 »

you have to understand how a program with windows works.
That's my problems ,I still think that everthing goes sequential as long a time ago.
Post Reply