Hi,
I would like to know, if it is stable to use WaitWindowEvent(variable.i) with a sometimes between the calls changed integer variable?
I understand, that WaitWindowEvent will come back faster then the variable timeout, when there are new events, and this wouldn't be a problem.
But mostly on Win10 it looks to me, that sometimes WaitWindowEvent doesn't come back, when the variable timeout should have been reached long ago.
In the manual I haven't found a clear info, if the timeout possibly has to be a constant or it also could be a changed variable, the compiler doesn't complain about my variable. Also there are no hints about the reliability of this timeout in the manual.
For example at AddWindowTimer there is a hint in the manual, that these timers will possibly not be near to exact, because they have low priority.
My use case: I wrote a PB program waiting for a job-file from a good old DOS program, doing the job(s) and answering with a file to the DOS program.
I set the variable when my program only waits for a new job from the DOS program to a timeout of 250ms.
But when doing different jobs I use timeouts between 25 and 250ms for WaitWindowEvent. The real jobs started by my program are done async on external devices with communication through Tcp/Ip or serial/com-port or filesystem and also need some time.
In general this works good, but sometimes and mostly on Win10 it looks to me, that WaitWindowEvent(variable.i) and variable with changing values of 25, 50, 100 or 250 sometimes for some seconds doesn't come back, so starting of a new job or working on an actual job sometimes really gets slow, and when for example moving the mouse wake up and become fast.
Putting an additional AddWindowTimer with for example 100ms makes everything faster, although these timer events have low priority according to the manual.
I know that I possibly could solve the timing problems with threads and Delay(), but this would be a really new experience with a big possibility of a lot new mistakes and bugs for me.
Does anyone have any tips for me?
Greetings and happy easter,
Hoerbie
Is WaitWindowEvent(variable) usable or is it unstable?
Re: Is WaitWindowEvent(variable) usable or is it unstable?
I assume that you are doing the asynchronous processing in threads.
Just send a PostEvent to the GUI that the processing is done. You can also transmit an EventData with the PostEvent.
But remember that an open "menu" stops the event loop.
Small simple example
Just send a PostEvent to the GUI that the processing is done. You can also transmit an EventData with the PostEvent.
But remember that an open "menu" stops the event loop.
Small simple example
Code: Select all
;-TOP
Enumeration Windows
#Main
EndEnumeration
Enumeration Gadgets
EndEnumeration
Enumeration Status
#MainStatusBar
EndEnumeration
Enumeration CustomEvent #PB_Event_FirstCustomValue
#MyEvent_ThreadFinished
EndEnumeration
Procedure thWork(id)
Delay(Random(5000, 2000))
PostEvent(#MyEvent_ThreadFinished, 0, 0, 0, id)
EndProcedure
Procedure Main()
#MainStyle = #PB_Window_SystemMenu | #PB_Window_MaximizeGadget | #PB_Window_MinimizeGadget
If OpenWindow(#Main, #PB_Ignore, #PB_Ignore, 800, 600, "Window" , #MainStyle)
CreateThread(@thWork(), 1)
CreateThread(@thWork(), 2)
CreateThread(@thWork(), 3)
Repeat
Select WaitWindowEvent()
Case #PB_Event_CloseWindow
Break
Case #MyEvent_ThreadFinished
Debug "Thread Finished ID " + EventData()
EndSelect
ForEver
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
PB v3.30 / v5.75 - OS Mac Mini OSX 10.xx - VM Window Pro / Linux Ubuntu
Downloads on my Webspace / OneDrive
Re: Is WaitWindowEvent(variable) usable or is it unstable?
Interesting , looking at the example in the reply, I didn't realize you could use the same procedure multiple times by threading.
Re: Is WaitWindowEvent(variable) usable or is it unstable?
Hi,
@mk-soft: Thanks for the example, but I'm actually not doing the jobs in one or multiple thread(s). There is simply one (sub)job that can be done at a time on the device, maybe directly followed by other (sub)jobs, but always only one device, so no really parallel work needed.
On all my PCs it works perfectly with doing all work (getting job from old prog, sending job to device, waiting, getting job answer from device, sending answer to old prog) in the event queue one after one. And modifying the timeout variable for the next call of WaitWindowEvent(timeout) seems to work too, when needed for different jobs.
But although calling WaitWindowEvent(timeout) with timeout=25 or timeout=100 etc. sometimes Win10 waits for multiple seconds without coming back to the event queue, but when moving the mouse it gets back to work, and using AddWindowTimer works better too.
I'm willing to give threads a try, but after getting problems with the timing of WaitWindowEvent(timeout), I need to be sure, that the timing of Delay(waitmilliseconds) is really reliable and not stopping like the event-queue?
And I'm really anxious to get a lot of new problems, as I've never needed and used threads until now, all the mutex, lock, thread safe stuff etc. are new to me.
Greetings, Hoerbie
@mk-soft: Thanks for the example, but I'm actually not doing the jobs in one or multiple thread(s). There is simply one (sub)job that can be done at a time on the device, maybe directly followed by other (sub)jobs, but always only one device, so no really parallel work needed.
On all my PCs it works perfectly with doing all work (getting job from old prog, sending job to device, waiting, getting job answer from device, sending answer to old prog) in the event queue one after one. And modifying the timeout variable for the next call of WaitWindowEvent(timeout) seems to work too, when needed for different jobs.
But although calling WaitWindowEvent(timeout) with timeout=25 or timeout=100 etc. sometimes Win10 waits for multiple seconds without coming back to the event queue, but when moving the mouse it gets back to work, and using AddWindowTimer works better too.
I'm willing to give threads a try, but after getting problems with the timing of WaitWindowEvent(timeout), I need to be sure, that the timing of Delay(waitmilliseconds) is really reliable and not stopping like the event-queue?
And I'm really anxious to get a lot of new problems, as I've never needed and used threads until now, all the mutex, lock, thread safe stuff etc. are new to me.
Greetings, Hoerbie
Re: Is WaitWindowEvent(variable) usable or is it unstable?
You can also create one or more master threads and start work threads in them.
To wait for the work threads, I wrote a simple job manager.
To do this, the data structure of the work thread must always be extended with the structure "udtJobData".
To create the master thread, use the function CreateJobMaster.
To create work threads, use the function CreateJobWork.
In addition, there is the thread function JobSignal for work threads and the functions JobWait and JobTry for the master thread.
To wait for the work threads, I wrote a simple job manager.
To do this, the data structure of the work thread must always be extended with the structure "udtJobData".
To create the master thread, use the function CreateJobMaster.
To create work threads, use the function CreateJobWork.
In addition, there is the thread function JobSignal for work threads and the functions JobWait and JobTry for the master thread.
Code: Select all
;-TOP
; Comment : Simple Thread Job Management
; Author : mk-soft
; Version : 1.01.0
; Create : 03.04.2021
; ********
EnableExplicit
CompilerIf Not #PB_Compiler_Thread
CompilerError "Use Compiler Option ThreadSafe!"
CompilerEndIf
; ----
Structure udtJobEvent
Semaphore.i
Mutex.i
List *Data()
EndStructure
Structure udtJobData
*JobEvent.udtJobEvent
Thread.i
Exit.i
Type.i
EndStructure
Structure udtJobMaster Extends udtJobData
JobEventData.udtJobEvent
EndStructure
; ----
Procedure JobSignal(*JobData.udtJobData)
Protected *JobEvent.udtJobEvent = *JobData\JobEvent
With *JobEvent
LockMutex(\Mutex)
LastElement(\Data())
AddElement(\Data())
\Data() = *JobData
SignalSemaphore(\Semaphore)
UnlockMutex(\Mutex)
EndWith
EndProcedure
; ----
Procedure JobWait(*JobData.udtJobData)
Protected *JobEvent.udtJobEvent = *JobData\JobEvent
Protected *Data
With *JobEvent
WaitSemaphore(\Semaphore)
LockMutex(\Mutex)
If FirstElement(\Data())
*Data = \Data()
DeleteElement(\Data())
EndIf
UnlockMutex(\Mutex)
EndWith
ProcedureReturn *Data
EndProcedure
; ----
Procedure JobTry(*JobData.udtJobData)
Protected *JobEvent.udtJobEvent = *JobData\JobEvent
Protected *Data
With *JobEvent
If TrySemaphore(\Semaphore) > 0
LockMutex(\Mutex)
If FirstElement(\Data())
*Data = \Data()
DeleteElement(\Data())
EndIf
UnlockMutex(\Mutex)
EndIf
EndWith
ProcedureReturn *Data
EndProcedure
; ----
Procedure CreateJobMaster(*Callback, *JobMaster.udtJobMaster)
With *JobMaster
\JobEvent = *JobMaster\JobEventData
\JobEventData\Mutex = CreateMutex()
\JobEventData\Semaphore = CreateSemaphore()
\Exit = #False
\Thread = CreateThread(*Callback, *JobMaster)
EndWith
EndProcedure
; ----
Procedure CreateJobWork(*Callback, *JobMaster.udtJobMaster, *JobData.udtJobData, JobType)
With *JobData
\JobEvent = *JobMaster\JobEvent
\Exit = #False
\Type = JobType
\Thread = CreateThread(*Callback, *JobData)
EndWith
EndProcedure
; ----
; ****
Enumeration Windows
#Main
EndEnumeration
Enumeration Gadgets
EndEnumeration
Enumeration Status
#MainStatusBar
EndEnumeration
Enumeration CustomEvent #PB_Event_FirstCustomValue
#MyEvent_ThreadFinished
EndEnumeration
; ----
Structure udtWorkData1 Extends udtJobData
iVal.i
EndStructure
Structure udtWorkData2 Extends udtJobData
sVal.s
EndStructure
; ----
Global JobMaster.udtJobMaster
Global JobWork1.udtWorkData1
Global JobWork2.udtWorkData1
Global JobWork3.udtWorkData2
; ----
Procedure thJobWork1(*pData.udtWorkData1)
With *pData
Delay(Random(5000, 2000))
*pData\iVal = Random(10)
JobSignal(*pData)
EndWith
EndProcedure
Procedure thJobWork2(*pData.udtWorkData2)
With *pData
Delay(Random(5000, 2000))
*pData\sVal = "Hello World!"
JobSignal(*pData)
EndWith
EndProcedure
; ----
Procedure thJobMaster(*JobMaster.udtJobMaster)
Protected *Data.udtJobData
Protected *Data1.udtWorkData1, *Data2.udtWorkData2
; Create Jobs
CreateJobWork(@thJobWork1(), @JobMaster, @JobWork1, 1)
CreateJobWork(@thJobWork1(), @JobMaster, @JobWork2, 1)
CreateJobWork(@thJobWork2(), @JobMaster, @JobWork3, 2)
; Wait
Repeat
*Data = JobWait(*JobMaster)
;*Data = JobTry(*JobMaster)
If *JobMaster\Exit
Break
EndIf
If *Data
; Type of Thread
Select *Data\Type
Case 1
*Data1 = *Data
Debug "Job Type 1: Value = " + *Data1\iVal
Case 2
*Data2 = *Data
Debug "Job Type 2: String = " + *Data2\sVal
EndSelect
PostEvent(#MyEvent_ThreadFinished, 0, 0, 0, *Data\Type)
Else
Delay(10)
EndIf
ForEver
EndProcedure
; ----
Procedure Main()
#MainStyle = #PB_Window_SystemMenu | #PB_Window_MaximizeGadget | #PB_Window_MinimizeGadget
If OpenWindow(#Main, #PB_Ignore, #PB_Ignore, 400, 200, "Thread Example" , #MainStyle)
CreateJobMaster(@thJobMaster(), @JobMaster)
Repeat
Select WaitWindowEvent()
Case #PB_Event_CloseWindow
Break
Case #MyEvent_ThreadFinished
Debug "Thread Finished Type " + EventData()
EndSelect
ForEver
JobMaster\Exit = #True
JobSignal(JobMaster)
WaitThread(JobMaster\Thread)
EndIf
EndProcedure : Main()
Last edited by mk-soft on Sat Apr 03, 2021 4:49 pm, edited 1 time in total.
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
PB v3.30 / v5.75 - OS Mac Mini OSX 10.xx - VM Window Pro / Linux Ubuntu
Downloads on my Webspace / OneDrive
Re: Is WaitWindowEvent(variable) usable or is it unstable?
We'd need to see your code to see what you're doing. But WaitWindowEvent(variable.i) is reliable, yes. Sounds like a coding error on your part (sorry).hoerbie wrote:it looks to me, that WaitWindowEvent(variable.i) and variable with changing values of 25, 50, 100 or 250 sometimes for some seconds doesn't come back