Multitasking using events

BlitzMax Forums/BlitzMax Programming/Multitasking using events

ImaginaryHuman(Posted 2006) [#1]
I have some questions about how multitasking works with events.

1. I know that in the o/s, the program that manages the GUI interface, input and manipulation from the user, etc, runs in its own thread/process so that it can be pre-emptively multitasked along with any other programs running on the computer. This is so that the GUI remains responsive and the user can do things such as move or resize windows and click buttons even when other programs are doing stuff. Is that correct and does it apply to all three platforms?

2. When I add a hook function to trap events from the GUI, ie in MaxGUI, anything that my hook does is being called from within the GUI's thread/process as if part of that thread/process, and is therefore multitasking alongside any `main program loop` I might have in my program and competing with it for time. So my hook function and my main code loop are essentially running as two separate threads that pre-empt each other. Is that a correct description of what is happening?

3. To avoid one part of your program clashing with another part in this way, ie a main program loop being too CPU-hungry and causing the GUI to slow down because there isn't enough time left for the GUI thread, you should get rid of the main loop as much as possible (have a WaitEvent() only), and put all main loop stuff into some other event hook such as the TIMERTICK or GADGETPAINT, so that the whole program is run from events. Is that a correct description/concept?

4. Because the hook function is called `as part of` the o/s's GUI process, the o/s doesn't put any more events into OUR event queue until we return from our hook function. In other words, events don't pre-empt other events in our queue, right? So we should be careful not to spend too much time in a given event if we're waiting for another more important event like a TIMERTICK?

5. Since the hook is called from the GUI thread, and is multitasking separately from the rest of our program, so long as we return from the hook soon enough, we could set up timers for each `virtual thread` that we could use as our own way of switching between tasks and allocating timeslices. Then whenever a TIMERTICK happens we can decide what timer it came from and then choose a function to call based on that, ie task switching. So events let us implement a rudimentary kind of multitasking within our app, right?

6. Since we would be multitasking parts of the app, we'd have to be careful of what else our app might be doing in a main loop because it would've been pre-empted and we can't be certain that current state will mess up if we touch it in the middle of something. But if we implemented our own `thread management` or semaphores/locks type of thing, we could fairly `safely` do pretty much anything in the hook using any other functions/variables that are part of the program?

7. Since the hook program uses the same variables and functions as all the rest of our program, all of that stuff including all data, objects, graphics etc, are all shared openly between the hook and the main program right?

8. In summary, you can use events to trigger custom `threads` of execution based on timed events, so long as you ideally can put a given thread on `hold` by returning from the hook at the end of its allowed timeslice and resume with it the next time around?

Any other issues or faults with this that you can see?


skidracer(Posted 2006) [#2]
There is no multithreading involved with hooks, they only execute when you call WaitEvent.


Dreamora(Posted 2006) [#3]
1) Yes, unless Linux user played around with their sources :)

2) No they are all in the same thread and handled linearly (so if the main function takes too long, it might happen that a different hooks event is lined up seveal times in the event queue).

3) Depending on the action the hook shall do, yes

4) Correct. And you never should forget to pass an event back to the queue (return data) if there is a different hook that might need it as well (alternative is in the codearchivs -> master event hook)

5) Yes. But the precision of the timer might come in as a problem there

6) Lock etc is not needed. As all runs in 1 thread, the situation where 2 different hooks / code parts try to access something can't come up. (the GC is not threadsafe, so using modules that add threading is a worse idea as well)

7) No. A hook is a function so its knowledge is restricted to its own variables and globals as with any other function

8) the only thing you can do with hooks is a simpler and especially "background controlled" timed programming like automatic updates of the physic calculates, drawing etc.
But you can't do anything like pause a thread or the like as you can't jump back to a specific position within a function.


So most likely you understood some parts of it, but everything refering to threads is wrong and thus I fear the summary as well ...

The only thing you can do through event hooks is let functions execute on their own without beeing part of a specific place in your mainloop.
But still: if a hook is running, the rest of the app is on halt.


ImaginaryHuman(Posted 2006) [#4]
Hmm, ok. Thanks for the feedback guys.

Here are some follow-up questions, then.

1. Do hooks get called when you use PollEvent() as well?

2. In my main loop if I use PeekEvent() to look at the queue and if there is no event I do some processing, but when there is an event I do PollEvent(), do the hooks then get called and executed when the PollEvent() occurs? Does PeekEvent trigger the hooks? Do the hooks trigger when the event arrives in the queue regardless of whether we look at it?

3. Do you HAVE to have a place in your program where you call WaitEvent(), WaitSystem() or PollEvent(), in order for any hooks to ever be run at all? Otherwise the hooks are never run because control isn't handed over to the system?

4. Dreamora's comment on point 5 - So even if the timer is pretty accurate at generating events, the execution of the TIMERTICK hook is only as accurate as how often I call WaitEvent() to trigger the check?

5. Dreamora's comment on point 7 - But a hook can call any other function anywhere in the program, plus access global variables, so only locally-made variables are limited to the scope of the hook function, right?

6. Dreamora's comment on point 8 - That's presuming that you can't `suspend` whatever is being executed in order to return and resume later. With a regular BlitzMax program you can't, but with scripts or some other interpretation engine you can.

7. Okay so as I understand it, the hook function is not given to the o/s as something it should jump to, rather when you call WaitSystem()/WaitEvent()/PollEvent() BlitzMax goes through each event in the queue and calls the hook function for each one?

8. I understand that the hook would not be pre-empted by anything in the main program loop. But if your main program is using PeekEvent() so that it only runs the hooks when there are some, that's sort of a way of `cooperatively multitasking` at least, even though it's not pre-emptive?

Thanks for your time.


Dreamora(Posted 2006) [#5]
@Skid: I don't think hooks need a waitevent to be executed. Otherwise none of my modules would work at all ... (i know, you are the programmer behind it - but BM itself does some event handling behind the scene even in polled mode which seems to keep them active and up to date)


1) Yes. I've a particle module that updates hook based while the game itself is fully with "keyhit etc" without any event based function call. (using a timer that activates it)

2) No, event hooks get activated automatically when a event comes in

3) Nope :-) They come themself.

4) No, but its accuracy is restricted to 1000 ticks per second which means 1 per ms, nothing in between. Thats what I meant. Using a timer with frequency of 1000 on the other side is no usefull solution.

5) If I understand you: right. A hook is the same as a function and underlies the same restriction

6) With a virtual machine that uses threading, you could perhaps. But I don't know enough about it, ask koriolis, he is the BVM man :-)

7) most likely yes. But waitevent has the pro, that it halts the app until an event comes in (saves cpu time and accu on notebooks!)

8) Don't understand the question I fear. Hooks are not bound to peekevent / waitevent ... the only thing those 2 give you is the events that happened - which is independent of the hooks that you can't control beside removing them.


Beaker(Posted 2006) [#6]
You don't seem to need a WaitEvent for hooks. This might be of interest to you:
http://www.blitzbasic.com/codearcs/codearcs.php?code=1690


ImaginaryHuman(Posted 2006) [#7]
Dreamora, so what you are saying is that as soon as the o/s generates an event and puts it in our queue, the hook is called, regardless of where you are in the main program loop or what else you are doing. So all events pre-empt anything outside of the hook, is what you're saying?

Then, to be friendly, you should do WaitEvent() to give the o/s some CPU time, which is sort of cooperatively letting the events happen. So if you DON'T do that, then your main program is competing with the o/s GUI code, right?

I thought this is how it worked, too, because the whole point of doing a hook is that you need it where the o/s is locked into a modal scenario and normally your app would be shut out from doing any processing while the user is in that modal situation. So the o/s has to be immediately triggering the hook code as and when the event happens, so that you can update things, right?

For example when you resize the window by dragging the corner, your app freezes and nothing happens until you stop moving the mouse, at which point an event is sent, and only that event gets executed, it returns, and then again your app is locked out until the user releases the mouse button.

The odd thing is that if you move the window with the title bar, while you are not moving the mouse it actually does allow TIMERTICK events to trickle through, even though after you've moved the mouse and you stop it also sends WINDOWMOVE events.

So it's kind of confusing.

I need to know exactly when the hook is called and how, and whether it pre-empts/immediately suspends the rest of your app while it's doing so. I'm getting conflicting answers from Skid, from Dreamora and from apparent behavior of actual programs.

(As to your point #6 Dreamora, yes the virtual machine would need to manage how it deals with multiple programs and time allocation and state preservation etc, but it is possible. I have my own system working. I'm just trying to see how it can be incorporated into event-driven stuff).


ImaginaryHuman(Posted 2006) [#8]
Thanks Beaker, useful to know things can be done with a separate timer. What I'm confused about is whether the o/s is deciding when the hook is called, or BlitzMax based on some request from our program.


skidracer(Posted 2006) [#9]
Hmm yes sorry other than WaitEvent, functions that call PollSystem and hence allow system events to be processed causing hooks to happen and events to be queued include:

PeekEvent
PollEvent
AppSuspended
AppTerminate
KeyHit
KeyDown
GetChar
FlushKeys
MouseX,Y,Z
FlushMouse
MouseHit
MouseDown
WaitKey
WaitChar
WaitMouse


Dreamora(Posted 2006) [#10]
so about anything that is more than a screensaver ;-)


ImaginaryHuman(Posted 2006) [#11]
Interesting. Thanks Mr Racer.

So even peeking at the queue will cause the hooks to be processed. .. .and the hooks are ONLY processed when one of the above commands is called?


Dreamora(Posted 2006) [#12]
No, using graphics will do it as well as this uses hooks behind the scene on its own. (polled input)


ImaginaryHuman(Posted 2006) [#13]
Does polled input just run some kind of timer and poll for an event when the timer is triggered, so it can get the mouse/keyboard input stuff?