Page 1 of 1

Gui menu select blocks thread ?

Posted: Sat Dec 23, 2017 4:13 pm
by Martt

Code: Select all

EnableExplicit

Global Semaphore.i

Declare Main()
Declare Thread(*Dummy)

Enumeration #PB_Event_FirstCustomValue
    #Thread_Finished
    #Thread_AddText
EndEnumeration

Enumeration
    #MAIN_WINDOW
    #EDITOR_WINDOW
    #MENU
    #FILE_RUN
    #FILE_QUIT
EndEnumeration

Procedure Main()

    Protected Exit.b
    Protected Event.i
    Protected Thread.i
    
    #Width  = 400
    #Height = 400
    #Space = 10
    
    OpenWindow(#MAIN_WINDOW, 100, 100, #Width, #Height, "Main Window")
    EditorGadget(#EDITOR_WINDOW, #Space, #Space, #Width - (#Space * 2), #Height - MenuHeight() - (#Space * 2), #PB_Editor_ReadOnly)
    
    CreateMenu(#MENU, WindowID(#MAIN_WINDOW))
        MenuTitle("File")
            MenuItem(#FILE_RUN,  "Run")
            MenuItem(#FILE_QUIT, "Quit")
        
    Repeat
        Select WaitWindowEvent()
            Case #PB_Event_CloseWindow
                Exit = #True
                
            Case #Thread_AddText
                AddGadgetItem(#EDITOR_WINDOW, -1, PeekS(EventData()))
                ; Goto last character (auto scroll)
                SendMessage_(GadgetID(#EDITOR_WINDOW), #EM_SETSEL, -1, -1)
                SignalSemaphore(Semaphore)

            Case #Thread_Finished
                DisableMenuItem(#MENU, #FILE_RUN, #False)
                SignalSemaphore(Semaphore)                
                
            Case #PB_Event_Menu
                Event = EventMenu()
                Select Event
                    Case #FILE_RUN
                        DisableMenuItem(#MENU, #FILE_RUN, #True)
                        Thread = CreateThread(@Thread(), #Null)
                        
                    Case #FILE_QUIT
                        Exit = #True
                EndSelect
        EndSelect
    Until Exit
    
    ; Kill thread if needed...
    If IsThread(Thread) : KillThread(Thread) : EndIf
    
    FreeMenu(#MENU)
    CloseWindow(#MAIN_WINDOW)

EndProcedure

Procedure Thread(*Dummy)
    
    Protected LoopCnt.i
    Protected Output.s
    
    For LoopCnt = 1 To 10000
        Output = "This string is number " + Str(LoopCnt)
        
        ; Send output to gui and wait for gui to process...
        Semaphore = CreateSemaphore()

        PostEvent(#Thread_AddText, #Null, #Null, #Null, @Output)
        WaitSemaphore(Semaphore)
        FreeSemaphore(Semaphore)
    Next
    
    ; Done, let the gui know were done...
    Semaphore = CreateSemaphore()

    PostEvent(#Thread_Finished, #Null, #Null, #Null, #Null)
    WaitSemaphore(Semaphore)
    FreeSemaphore(Semaphore)

EndProcedure

Main()
End
Newbie question here. In this test program, the menuoption File->Run will run the thread. But if the thread is running and I click on File, the thread stops displaying output. Likely because of the Semaphore.
Is there a way around it besides HideMenu(), which messes up the coordinates of the editorgadget ?

Re: Gui menu select blocks thread ?

Posted: Sat Dec 23, 2017 4:54 pm
by infratec
Hi,

the thread is still running, but paused by waiting on the semaphore.
The main eventloop is stooped by your menu access, so it can not process the Events.

You can avoid this by using BindEvent()

Code: Select all

EnableExplicit

Structure ThreadParameterStructure
  Thread.i
  Semaphore.i
  Exit.i
EndStructure



Declare Main()
Declare Thread(*Dummy)

Enumeration #PB_Event_FirstCustomValue
  #Thread_Finished
  #Thread_AddText
EndEnumeration

Enumeration
  #MAIN_WINDOW
  #EDITOR_WINDOW
  #MENU
  #FILE_RUN
  #FILE_QUIT
EndEnumeration

Global ThreadParameter.ThreadParameterStructure

Procedure Test()
  AddGadgetItem(#EDITOR_WINDOW, -1, PeekS(EventData()))
  SendMessage_(GadgetID(#EDITOR_WINDOW), #EM_SETSEL, -1, -1)
  SignalSemaphore(ThreadParameter\Semaphore)
EndProcedure


Procedure Main()
  
  Protected Exit.b
  Protected Event.i
  Protected Thread.i
  ;Protected ThreadParameter.ThreadParameterStructure
  
  #Width  = 400
  #Height = 400
  #Space = 10
  
  OpenWindow(#MAIN_WINDOW, 100, 100, #Width, #Height, "Main Window")
  EditorGadget(#EDITOR_WINDOW, #Space, #Space, #Width - (#Space * 2), #Height - MenuHeight() - (#Space * 2), #PB_Editor_ReadOnly)
  
  CreateMenu(#MENU, WindowID(#MAIN_WINDOW))
  MenuTitle("File")
  MenuItem(#FILE_RUN,  "Run")
  MenuItem(#FILE_QUIT, "Quit")
  
  ThreadParameter\Semaphore = CreateSemaphore()
  
  BindEvent(#Thread_AddText, @Test())
  
  Repeat
    Select WaitWindowEvent()
      Case #PB_Event_CloseWindow
        Exit = #True
        
;       Case #Thread_AddText
;         AddGadgetItem(#EDITOR_WINDOW, -1, PeekS(EventData()))
;         ; Goto last character (auto scroll)
;         SendMessage_(GadgetID(#EDITOR_WINDOW), #EM_SETSEL, -1, -1)
;         SignalSemaphore(ThreadParameter\Semaphore)
        
      Case #Thread_Finished
        DisableMenuItem(#MENU, #FILE_RUN, #False)
        
      Case #PB_Event_Menu
        Event = EventMenu()
        Select Event
          Case #FILE_RUN
            DisableMenuItem(#MENU, #FILE_RUN, #True)
            ThreadParameter\Thread = CreateThread(@Thread(), @ThreadParameter)
            
          Case #FILE_QUIT
            Exit = #True
        EndSelect
    EndSelect
  Until Exit
  
  ; Kill thread if needed...
  If IsThread(Thread)
    ThreadParameter\Exit = #True
    If WaitThread(ThreadParameter\Thread, 1000) = 0
      KillThread(ThreadParameter\Thread)
    EndIf
  EndIf
  
  FreeSemaphore(ThreadParameter\Semaphore)
  
  FreeMenu(#MENU)
  CloseWindow(#MAIN_WINDOW)
  
EndProcedure

Procedure Thread(*Parameter.ThreadParameterStructure)
  
  Protected LoopCnt.i
  Protected Output.s
  
  For LoopCnt = 1 To 10000
    Output = "This string is number " + Str(LoopCnt)
    
    ; Send output to gui and wait for gui to process...
    PostEvent(#Thread_AddText, #Null, #Null, #Null, @Output)
    WaitSemaphore(*Parameter\Semaphore)
  Next
  
  PostEvent(#Thread_Finished, #Null, #Null, #Null, #Null)
  
EndProcedure

Main()
I also eliminated your CreateSemaphore() marathon :wink:

Bernd

Re: Gui menu select blocks thread ?

Posted: Sat Dec 23, 2017 5:10 pm
by srod
Yes Windows will enter a modal event loop when a menu is opened which will block the main process's message retrieval. Your thread still runs, but it is of course waiting for your semaphore to be signaled which won't happen until Window's releases the message queue etc.

You can make the menu modeless with the #MNS_MODELESS flag, but you'll need to do this through API and you'll end up with a menu which won't behave the way your user's expect! :)

**EDIT : now I didn't think of using BindEvent()! :) Nice one.

Re: Gui menu select blocks thread ?

Posted: Sat Dec 23, 2017 6:11 pm
by skywalk
Nice 8)
I did not expect BindEvent() to update the gui while the user interacts with the gui?
So, BindEvent()'s can access GUI elements, while our threads cannot.

Re: Gui menu select blocks thread ?

Posted: Sat Dec 23, 2017 6:14 pm
by srod
The event procedures are still being called in the context of the main process so there is no problem there. The menu modal loop will ensure that all controls still receive their paint events (else the controls will appear to freeze whilst a menu is displayed) and it is invariably here that our bound event procedures are being called.

Re: Gui menu select blocks thread ?

Posted: Sat Dec 23, 2017 6:38 pm
by skywalk
Yes, dropping bindevent() and applying the gui update in the main event loop, causes the original complaint of locking the thread. bindevent() is updating in parallel with the main event loop. Our threads do not have the same luxury.

Re: Gui menu select blocks thread ?

Posted: Sun Dec 24, 2017 6:39 am
by Martt
infratec wrote:Hi,

the thread is still running, but paused by waiting on the semaphore.
The main eventloop is stooped by your menu access, so it can not process the Events.

You can avoid this by using BindEvent()

I also eliminated your CreateSemaphore() marathon :wink:

Bernd
Thanks for the BindEvent. I did not expect Windows to stop the eventloop on a single menu click :oops: .
And the CreateSemaphore marathon, yeah.... Kind of dumb.

Thanks for the answer. Now the project can continue....

Re: Gui menu select blocks thread ?

Posted: Sun Dec 24, 2017 12:23 pm
by mk-soft
For easy work between threads and GUI i have wrote a module. Perhaps help this...

Link: Module ThreadToGUI

Re: Gui menu select blocks thread ?

Posted: Sun Dec 24, 2017 7:05 pm
by skywalk
Thanks mk-soft and infratec for pointing out the BindEvent() behavior with threads. :idea: