I have two questions regarding qelems (one of them is already asked in this thread: http://cycling74.com/forums/topic.php?id=41800 ):
qelem_unset() automatically called when we call
qelem_free(), or do we have to call this separately?
(2) The SDK (5.1.7) says in the description of the
A Qelem object is unset after its queue function has been called.
This is a bit confusing. What happens if another thread sets the qelem agan while the qelem task function is executing? According to the description, this should happen in that case:
(1) The qelem is set by some function.
(2) The qelem task function is executed at some point.
(3) In the meantime, the qelem will be set by another function in another thread.
(4) The qelem task function finishes its execution.
(5) The qelem will be unset.
If this is really the scenario, then this means that the second qelem call will simply ‘be lost’ and one will need to wait until somebody makes another qelem call, which is really, really weird…
Thanks for clarification,
Yes, qelem_free() automatically calls qelem_unset() internally.
If you call qelem_set() and it has already been set, but not yet serviced, the call does nothing.
Once it is serviced, the flag is unset and your queue function is triggered.
So yes, any attempts to set this in the intervening time will be "lost".
Some well known examples of this behavior are the qmetro and qlim objects. The qmetro, for example, enables Jitter processing to drop frames if the calculations take longer than the metro’s user-defined period.
If you don’t want to drop data then you can use defer_low(). It’s important to be cautious with defer_low(), however, to ensure that you don’t backlog the queue with too many events (which degrades Max’s performance).
thanks a lot for the reply. However, I’m a bit still confused. I understand that if a qelem gets set multiple times before serviced, then the queue function will be triggered only once. That’s clear.
However, what happens if the qelem gets set by a custom thread during the time when the queue function is actually running? According the SDK, the order is: first the queue function runs, then the qelem gets unset. On the other hand, your previous post (the sentence ‘the flag is unset and your queue function is triggered’) suggests that the flag will be unset before the queue function executes.
The main difference is that in the first case (when the flag gets unset after executing the queue function), if a custom thread sets the qelem during the very same time when the main thread is actually executing the queue function, that call will never be serviced. However, if the flag gets unset before the queue function is called, as your last reply suggests to me, these calls will be serviced in a next queued event.
Thanks for any clarification on this,
Ah, now I understand. A qelem should only be set by the main thread or the scheduler thread. It should *not* be set directly from any other thread.
What we do in Max when we need to trigger a qelem from an arbitrary thread is to set a clock, and our clock function will then set a qelem. It’s an extra step, but this is how it is intended to function.
thank you indeed! So, in order to prove that I really understood the things under the hood, am I OK to assume that the point behind using a clock to trigger the qelem is, that since both the qelem task and the clock task is scheduled to run in the main thread, this way I will avoid the scenario described above by myself (in other words, with this solution there’s no way to set a qelem while it’s associated task function is being executed)?
And BTW, is it enough to free the clock with
freeobject(), or do we need to
unset it first?
Thanks for all the explanations,
The clock may not, in fact, be serviced on the main thread. I *always* use Max with overdrive turned-on, as an example. In this case the scheduler is on its own thread. The qelem is designed specifically to check for the scheduler thread or main threads, which is why that works.
Yes, freeing a clock will automatically unset it.
I’m then still confused a bit. Does this mean that, if I have a clock that sets the qelem, it could still happen that a clock running on the scheduler thread would set the qelem just during the time while the qelem task is executing on the main thread? (In which case, the scheduled clock task would have no effect, I suppose.)
In other words: if I want to make sure that nothing gets lost, is there no other way than
defer_low()? I would like to avoid
defer_low() since I am more than fine if my ‘things’ get accumulated (for example, in a FIFO-like structure) and then they get processed only once-in-a-while (which is what a qelem would give me if I could make it work properly — as I understood, with
defer_low() I would get a new event for every ‘thing’ of mine, which might flood the main thread). However, I need to make sure that everything gets executed at some time and that none of my scheduled ‘things’ would get lost.
Thanks for the help,
the problem lies here:
A Qelem object is unset after its queue function has been called.
If I set the qelem at the end of the task, then (according to the SDK) it will be unset just after that. I must admit that I never tried whether this was actually true, but Tim also said the same thing…
well, I admit that my question is rather theoretical. I mean, what is the probability that a custom thread would set the qelem just at the same time when it executes on the main thread?
On the other hand, if I want to keep this question purely theoretical, then a clock might not work. If Overdrive is turned on, then the clock might execute on another thread than the qelem. That means the following scenario could happen:
- A running qelem task on the main thread checks for re-trigger and sets the clock for re-triggering as the last command in the qelem task function.
- The OS stops the main thread and starts serving the scheduler thread.
- The clock which has just been set, executes and sets the qelem.
- The OS stops the scheduler thread and starts serving the main thread.
- Max finishes the qelem execution and removes the qelem flag.
In this case, the qelem might never be triggered again, thus I might end up having events in my FIFO that would never be processed.
I know, I could play around with setting the clock to some other time than 0. But from a theoretical point of view that’s also not a solution, since I can’t make any assumptions about the time elapsing between two consequent executions of the same thread by the OS.
FYI, what I finally implemented is, that I have now two qelems. The first qelem runs my basic task, and then sets the second qelem. The second qelem checks the size of the FIFO, and if it’s nonzero, it will set the first qelem again. Ah, and by the way, there’s a clock that can be set from my custom threads that would trigger the first qelem to process the FIFO generated by the custom threads. Now I hope this would really solve all of my trouble… ;-)
Thanks for thinking loud and helping,