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.
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.