Page 1 of 1
MessageRequester() in a thread allowed or not
Posted: Wed Feb 27, 2013 9:25 pm
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
Re: MessageRequester() in a thread allowed or not
Posted: Wed Feb 27, 2013 9:34 pm
by ts-soft
Never use a Requester in a thread!
Re: MessageRequester() in a thread allowed or not
Posted: Wed Feb 27, 2013 9:56 pm
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.
Re: MessageRequester() in a thread allowed or not
Posted: Wed Feb 27, 2013 10:09 pm
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
Re: MessageRequester() in a thread allowed or not
Posted: Wed Feb 27, 2013 10:19 pm
by ts-soft
I have made a small example for you, but you are so fast
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
Re: MessageRequester() in a thread allowed or not
Posted: Tue Jan 15, 2019 1:06 am
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.
Re: MessageRequester() in a thread allowed or not
Posted: Tue Jan 15, 2019 10:50 pm
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()
Re: MessageRequester() in a thread allowed or not
Posted: Tue Jan 15, 2019 11:32 pm
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.
Re: MessageRequester() in a thread allowed or not
Posted: Wed Jan 16, 2019 1:10 pm
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