MessageRequester() in a thread allowed or not

Linux specific forum
infratec
Always Here
Always Here
Posts: 6817
Joined: Sun Sep 07, 2008 12:45 pm
Location: Germany

MessageRequester() in a thread allowed or not

Post by infratec »

Hi together,

I ran into a problem:

I use OpenSerialPort() and MessageRequester() in a thread.
In windoof everything works fine.
In Linux I got reproducable crashes.
But it depence on ???

It's difficult to explain.

I had to implement several different serial protocols in the same program.
I managed it with pointers to procedures.
The pointer is set to the needed procedure and opened as thread.

Inside of the thread is always OpenSerialPort() and sometimes MessagerRequester()
The OpenWindow() stuff which was used is replaced with PostEvent().
2 procedures are working and 2 not.
They are nearly identical at the start where the crash happens.

One time I saw a message from Linux XInitThread was not called ... (or something similar)
If I run it inside the IDE I only get an 'executable is termiated ...'
I tried also Purifier ... no better results.

So please can someone tell me if MessageRequester() and OpenSerialPort() and ioctl_() are threadsafe ?

Bernd
User avatar
ts-soft
Always Here
Always Here
Posts: 5756
Joined: Thu Jun 24, 2004 2:44 pm
Location: Berlin - Germany

Re: MessageRequester() in a thread allowed or not

Post by ts-soft »

Never use a Requester in a thread!
PureBasic 5.73 | SpiderBasic 2.30 | Windows 10 Pro (x64) | Linux Mint 20.1 (x64)
Old bugs good, new bugs bad! Updates are evil: might fix old bugs and introduce no new ones.
Image
uwekel
Enthusiast
Enthusiast
Posts: 740
Joined: Sat Dec 03, 2011 5:54 pm
Location: Oldenburg (Germany)

Re: MessageRequester() in a thread allowed or not

Post by uwekel »

Save the message into a global variable and query the variables content in the main event loop. That works! You should never access GUI elements from another thread.
PB 5.70 LTS (x64) - Debian Testing, Gnome 3.30.2
infratec
Always Here
Always Here
Posts: 6817
Joined: Sun Sep 07, 2008 12:45 pm
Location: Germany

Re: MessageRequester() in a thread allowed or not

Post by infratec »

Ok, ok,

I change everything to:

Code: Select all

PostEvent(#EventShowMessageRequester, #MainWindow, 0, 0, @Text$)
WaitSemaphore(MessageRequesterSemaphore)
Thank you very much, tomorrow I can try it.

Bernd
User avatar
ts-soft
Always Here
Always Here
Posts: 5756
Joined: Thu Jun 24, 2004 2:44 pm
Location: Berlin - Germany

Re: MessageRequester() in a thread allowed or not

Post by ts-soft »

I have made a small example for you, but you are so fast :wink:

Code: Select all

EnableExplicit

Structure MessageBox
  Title.s
  Text.s
  Flag.i
EndStructure

#MyThreadEvent = #PB_Event_FirstCustomValue

Procedure MyThread(dummy)
  Protected *mem.MessageBox = AllocateMemory(SizeOf(MessageBox))
  Delay(5000)
  *mem\Title = "My Title"
  *mem\Text = "Hello world from Thread"
  PostEvent(#MyThreadEvent, 0, -1, -1, *mem)
EndProcedure

OpenWindow(0, #PB_Ignore, #PB_Ignore, 640, 480, "")

Define Thread = CreateThread(@MyThread(), 0)
Define *mem.MessageBox

Repeat
  Select WaitWindowEvent()
    Case #PB_Event_CloseWindow
      WaitThread(Thread, 6000)
      Break
    Case #MyThreadEvent
      *mem = EventData()
      MessageRequester(*mem\Title, *mem\Text, *mem\Flag)
      FreeMemory(*mem)
  EndSelect
ForEver
Greetings - Thomas
PureBasic 5.73 | SpiderBasic 2.30 | Windows 10 Pro (x64) | Linux Mint 20.1 (x64)
Old bugs good, new bugs bad! Updates are evil: might fix old bugs and introduce no new ones.
Image
User avatar
skywalk
Addict
Addict
Posts: 3972
Joined: Wed Dec 23, 2009 10:14 pm
Location: Boston, MA

Re: MessageRequester() in a thread allowed or not

Post by skywalk »

infratec wrote:Ok, ok,
I change everything to:

Code: Select all

PostEvent(#EventShowMessageRequester, #MainWindow, 0, 0, @Text$)
WaitSemaphore(MessageRequesterSemaphore)
Thank you very much, tomorrow I can try it.
Bernd
Hi, I just noticed your posting on calling MessageRequester()'s from a thread.
My Windows app's do this without errors or lockups.
Was I just lucky?
My assumption is PB's MessageRequester() is modal or blocking in the Windows lib.
Not sure about Linux/MAC?
Searching this topic seems to give conflicting answers?
MessageBoxes and worker threads
I really want to avoid creating PostEvent()'s for modal dialog boxes called from my various threads. :oops:
The nice thing about standards is there are so many to choose from. ~ Andrew Tanenbaum
User avatar
mk-soft
Always Here
Always Here
Posts: 5333
Joined: Fri May 12, 2006 6:51 pm
Location: Germany

Re: MessageRequester() in a thread allowed or not

Post by mk-soft »

Everything that has to do with GUI must always be processed in the MainThread.

With the MessageRequester via PostEvent to open I had a behaviour under MacOS which I didn't want to do to the user. This could open several times via thread.

So I block the requester in my module ThreadToGUI via a mutex.

Edit...

To open dialogs via threads its only wirk over PostEvent, because we can only create window and gadget inside the MainThread

Code: Select all

;-TOP

; Example ThreadToGUI SendEvent with open Dialog

IncludeFile "Modul_ThreadToGUI.pb"

UseModule ThreadToGUI

Enumeration
  #Window
  #Dialog
EndEnumeration

Enumeration
  #Dialog_Ok
  #Dialog_Cancel
  #Dialog_List
EndEnumeration

;- Test

;- Constants
Enumeration #PB_Event_FirstCustomValue
  #My_Event_OpenDialog
EndEnumeration

Structure udtDialogData
  Array TextList.s(0)
EndStructure

Procedure Test(Null)
  
  Protected result, index, daten.udtDialogData
  
  Debug "Init Thread"
  
  Dim daten\TextList(9)
  For index = 0 To ArraySize(daten\TextList())
    daten\TextList(index) = "Eintrag " + Str(index)
  Next
  
  Repeat
    Delay(1000)
    result = SendEvent(#My_Event_OpenDialog, 0, 0, 0, @daten)
    If result >= 0
      Debug "Result: " + daten\TextList(result)
    Else
      Debug "Abbruch!"
      Break
    EndIf
  ForEver
  
  Debug "Exit Thread"
  
EndProcedure

Procedure OpenDialog(*Daten.udtDialogData)
  Protected index
  If OpenWindow(#Dialog, #PB_Ignore, #PB_Ignore, 400, 300, "Example Threaded Dialog")
    ListViewGadget(#Dialog_List, 5, 5, 380, 240)
    ButtonGadget(#Dialog_Ok, 5, 260, 120, 25, "Ok")
    ButtonGadget(#Dialog_Cancel, 270, 260, 120, 25, "Abbrechen")
    For index = 0 To ArraySize(*Daten\TextList())
      AddGadgetItem(#Dialog_List, index, *Daten\TextList(index))
    Next
    ProcedureReturn #True
  Else
    ProcedureReturn #False
  EndIf
EndProcedure

Procedure Main()
  Protected MyEventOpenDialog, result
  
  If OpenWindow(#Window, 0, 0, 400, 200, "Example SendEvent", #PB_Window_MinimizeGadget|#PB_Window_ScreenCentered)
    
    UseModule ThreadToGUI
    
    hThread = CreateThread(@Test(), #Null)
    
    Repeat
      
      Select WaitWindowEvent()
          
        Case #PB_Event_CloseWindow
          If EventWindow() = #Window
            exit = 1
          EndIf
          
        Case #PB_Event_Gadget
          Select EventGadget()
            Case #Dialog_Ok
              result = GetGadgetState(#Dialog_List)
              CloseWindow(#Dialog)
              DispatchEvent(MyEventOpenDialog, result)
            Case #Dialog_Cancel
              CloseWindow(#Dialog)
              result = -1
              DispatchEvent(MyEventOpenDialog, result)
          EndSelect
          
        Case #My_Event_OpenDialog
          MyEventOpenDialog = EventData()
          OpenDialog(SendEventData(MyEventOpenDialog))
          
      EndSelect
      
    Until exit
    If IsThread(hThread)
      Debug "Thread läuft"
      KillThread(hThread)
    EndIf
    
  EndIf
EndProcedure : Main()
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
User avatar
skywalk
Addict
Addict
Posts: 3972
Joined: Wed Dec 23, 2009 10:14 pm
Location: Boston, MA

Re: MessageRequester() in a thread allowed or not

Post by skywalk »

So far, I have not had a case where more than 1 thread called a MessageRequester()?
I am confused by that scenario anyway, since how can the OS display more than 1 modal dialog?
Which 1 is the leader?

Do you have an example code with 2 threads each calling a MessageRequester()?
EDIT: haha, you posted too fast!

I am still unconvinced in Windows at least, that a thread cannot call MessageRequester()?
The thread is not creating a main window, only a subordinate, but modal(blocking) dialog that should be owned by the main window.
The nice thing about standards is there are so many to choose from. ~ Andrew Tanenbaum
User avatar
mk-soft
Always Here
Always Here
Posts: 5333
Joined: Fri May 12, 2006 6:51 pm
Location: Germany

Re: MessageRequester() in a thread allowed or not

Post by mk-soft »

The main window of the MessageRequerster is locked,
but two MessageReguester are opened when they are called in the thread.
I can't say how stable this works on Windows. But it is not advantageous if several requesters are started.
Under Linux and MacOS you are not allowed to start the requester from threads, because this leads to a crash...

Code: Select all

;-TOP

; Example ThreadToGUI SendEvent

IncludeFile "Modul_ThreadToGUI.pb"

Enumeration
  #Window
EndEnumeration

;- Test

;- Constants
Enumeration #PB_Event_FirstCustomValue
  #My_Event_GUI
  #My_Event_Question
EndEnumeration

Procedure thWork(ID)
  
  Protected result, cnt
  
  Debug "Init Thread"
  ;MySemaphore = CreateSemaphore()
  
  Repeat
    Delay(500)
    cnt + 1
    ;result = MessageRequester("Questions", "Continue " + ID, #PB_MessageRequester_YesNoCancel)
    ;result = ThreadToGUI::SendEvent(#My_Event_Question, 0, 0, 0, ID * 1000 + cnt)
    result = ThreadToGUI::DoMessageRequester("Questions", "Continue " + ID, #PB_MessageRequester_YesNoCancel)
    Select result
      Case #PB_MessageRequester_Yes
        Debug "Result Yes"
      Case #PB_MessageRequester_No
        Debug "Result No"
      Case #PB_MessageRequester_Cancel
        Debug "Result Cancel"
    EndSelect
  Until result = #PB_MessageRequester_Cancel
  
  If MySemaphore
    FreeSemaphore(MySemaphore)
  EndIf
  
  Debug "Exit Thread"
  
EndProcedure

Global MyEvent

If OpenWindow(#Window, 0, 0, 800, 600, "Example SendEvent", #PB_Window_MinimizeGadget|#PB_Window_ScreenCentered)
  
  UseModule ThreadToGUI
  
  hThread = CreateThread(@thWork(), 1)
  hThread2 = CreateThread(@thWork(), 2)
  
  BindEventGUI(#My_Event_GUI)
  
  Repeat
    
    Select WaitWindowEvent()
        
      Case #PB_Event_CloseWindow
        exit = 1
        
      Case #PB_Event_Gadget
        
      Case #My_Event_Question
        MyEvent = EventData()
        Value = SendEventData(MyEvent)
        Debug "Incomming Message from thread. Data: " + Str(Value)
        result = MessageRequester("Questions", "Continue " + Value, #PB_MessageRequester_YesNoCancel)
        DispatchEvent(MyEvent, result)
        
    EndSelect
    
  Until exit
  If IsThread(hThread)
    Debug "Kill Thread"
    KillThread(hThread)
  EndIf
  If IsThread(hThread2)
    Debug "Kill Thread 2"
    KillThread(hThread2)
  EndIf
  
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
Post Reply