How to use threads in a sketch?

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() ?

1 Like

Callback serialEvent() is already invoked by Serial’s thread:
Processing.org/reference/libraries/serial/serialEvent_.html

So it can act as a “producer” thread like in this example:

1 Like

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.

1 Like

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!

Maybe you can try to call wait() inside callback post() as a workaround:
Processing.GitHub.io/processing-javadocs/core/processing/core/PApplet.html#registerMethod-java.lang.String-java.lang.Object-

1 Like

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.

1 Like

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:

  1. Upon the receipt of data on the serial bus
  2. 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?

1 Like

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.

Kf

1 Like

Belatedly:

No, it can’t, not as described.

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.

So:

void draw() {
  if(receiptOfData || inputEvent) {
    screenUpdate();
  }
}

void screenUpdate() {
  // background
  // gui elements
  // etc.
}

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.

1 Like