The need has arisen to make the draw() function the run function of a consumer thread that receives from a producer thread, as is demonstrated in this example:
In my application the producer thread reads data from a serial bus, and then I need the draw function to execute its loop to act on it, and display the data.
I also need the draw function to display more than the data from the serial bus, and to update the user interface whenever that is ready also. Hence the need for multiple threads.
I would need the draw() function to be that consumer threadâs run() function, and would need a wait() function in the draw loop to wait for a notification. In the example linked to above the synchronization object is taskQueue. In a sketch, since draw() is already a thread, would it work to create only, say, a taskQueue synchronization object, then an additional producer thread using that âtaskQueueâ object, and within the draw function, call taskQueue.wait() ?
serialEvent() would make unnecessary the creation of another thread. But it alone does not solve the problem.
I need the draw() loop to iterate not just on input data from the serial port, but also when an event is triggered from the user interface. This means it will not work for the draw() loop to block on serial port events alone. I need the draw() loop to block until notified, so it can be notified of both the arrival of data on the serial port, and also GUI interface events the user has triggered.
I am hoping the block in the draw() loop can be done by a synchronization objectâs wait() method, which can be notified by both user interface events, and serial port data arrival events.
Which GUI ru using? G4P, ControlP5 or something else?
If it happens to be those 2 Iâve listed above, I donât believe you can block the âAnimation Threadâ, b/c AFAIK those 2 libraries rely on it, and would block as well.
If itâs some other GUI which got its own Thread, you might be able to use such wait() / notify() approach.
Even so, you canât call wait() while draw() is running, b/c Processing only renders the current frame later, after draw() returns!
But before committing to any complex approach, you should consider whether a simpler, non-synchronized() solution would be just enough.
If you merely have some container and/or set of global variables which replace their old value w/ the 1 which has just arrived, you donât need any Thread stuff.
You simply iterate over the set of values and display something based on those.
However, if you need to accumulate some or all of the received data, then youâll need synchronized() blocks in order to atomize add() & remove() operations, plus its loop.
I tried execute noLoop() in setup(), and in the ControlP5, and Serial, class handlers call redraw(). The front panel controls did not work until I removed noLoop() from setup(). So you are right that ControlP5 relies on the draw() iterating regularly.
The removal of noLoop() is not an acceptable solution. Having it iterate repeatedly like that is like polling. It wastes too much processor time. It is evident now that ControlP5 does not use interrupts. Is there a button library that does?
Another approach might be to create my own handler for mouse events, to be triggered on a button click. This would then notify the wait in the draw function, and unblock it so it can do the loop that processes the ControlP5 button.
There are only two conditions for which I need the frame to update:
Upon the receipt of data on the serial bus
A mouse button click on a ControlP5 control.
So I can have a wait in the draw function if it can be coded to unblock on the above two conditions. The question is can this wait in the draw function be made to work?
Is this your feeling or do you really have some serious CPU constrains? Mind showing some evidence? My recommendation is to use the KISS principle. If you want, you could set the frameRate() but I will do that second. You can use Processing to create a POC or a MVP and then you can see if you need to optimize. My two cents.
Processing has a single main loop. draw() exits, the screen is updated, and events (like key events and mouse events and gui library events and exit events) are processed, then draw() begins againi. You can modify event processing with the built-in keyPressed() mouseReleased etc., or use GUI libraries, but you donât poll for events inside draw. Draw is the loop, and you poll for events between frames.
It seems like you are running into a paradigm problem with processing, and trying to somehow create a loop inside draw(). In general, donât. draw() is the loop.
Now you arenât constantly redrawing your screen, but you also arenât blocking input events â including checking for exit(), which also only happens between draw frames. If you want interaction, donât lock your main application thread; donât block draw.