Adding a function to the "Processing Animation Thread"


#1

Hello everyone.

I have a question regarding adding a function to be ran in the Processing Animation Thread or, in other words, to be ran after draw() in a similar fashion as the keyPressed() and mousePressed() function.

Basically I am developing an application that receives UDP messages from Max and, when a UDP message is received (I’m using the function receive() from the UDP library to handle this) it triggers a function that affects the draw() function. The problem is that the UDP library seems to be running in a different thread, which is cuncurrent with the Processing Animation Thread and causes a race condition, that leads to acessing an out of bonds value in one of the tables used in draw(). If instead of receiving an UDP message to trigger the function, I use the keyPressed(), everything runs smoothly.

In the Processing source code inside core/PApplet.java, I’ve found this comment:

Processing uses active mode rendering. All animation tasks happen on the
“Processing Animation Thread”. The setup() and draw() methods are handled
by that thread, and events (like mouse movement and key presses, which are
fired by the event dispatch thread or EDT) are queued to be safely handled
at the end of draw().

For code that needs to run on the EDT, use EventQueue.invokeLater(). When
doing so, be careful to synchronize between that code and the Processing
animation thread. That is, you can’t call Processing methods from the EDT
or at any random time from another thread. Use of a callback function or
the registerXxx() methods in PApplet can help ensure that your code doesn’t
do something naughty.

Basically I would like to queue an event to be safely handled at the end of draw(), inside the UDP thread. I tried the invokeLater() function inside the receive() but it still had the same out of bonds error.
Another thing I think I can do is, inside the UDP receive(), generate a keyPressed event, any tips on how to do it?

Not sure I’m very clear but basicaly, I want to have a fucntion that handles UDP messages the same way that keyPressed() handles key presses.

Thank you very much!


#2

Hi, I think this is a common problem with several libraries, for example with oscP5. Unfortunately all the examples receiving data in oscP5 only print text to the console when most users probably would like to dodraw graphics in response to network input.

The way I’ve worked around this is to store data received via network, and then access that data at the end of the draw function.

In one case I used a ConcurrentHashMap to store the data. You can see that example here.

If you only need to modify the application state which is stored as primitive data types like ints and floats then you don’t need any concurrent data types, if I remember right you can just change those variables when the network activity happens and then read those variables from inside the draw loop.

Update: I just saw this on a different project of mine:

	@Override
	public void oscEvent(OscMessage msg) {
		if (msg.checkTypetag("ffffffff")) {
			synchronized (this) {
				for (int b = 0; b < BANDS; b++) {
					bands[b].valRecv = msg.get(b).floatValue();
				}
			}
		}
	}

I used synchronized to read and write to a specific variable. Not sure how much this affects performance.


#3
  • For most simple cases, a humble global boolean variable should be just enough.
  • Set it to true inside the threaded callback.
  • Then inside draw() keep checking whether it had become true.
  • If yes, set it back to false, and do the tasked drawing action there.

#4

If I recall correctly, for simple pre-draw and post-draw hooks, a normal sketch can also use registerMethod() with pre() and post(), just like a library.

I’m not sure if the lightweight form is useful for your application.

int x;
void setup() {
  registerMethod("post", this);
}
void draw() {
  println(x);
}
void post() {
  x = x+1;
}

#5

I followed GoToLoop’s approach, to use a flag inside the Receive() function that is used by the draw() and copied the code of the “reaction to the udp event” to the end of the draw loop. This did not work correctly but, after this, I added the “reaction” to the begging of the draw loop. It worked and everything is working correctly! Thank you all very much!


#6

I would suggest the using “pre” and/or “post” methods as suggested by @jeremydouglass. I have used these successfully in the G4P library -

  • pre to perform easing on the sliders and
  • post - to remove unwanted G4P controls to avoid concurrent access exceptions

#7

Shame there isn’t a version of invokeLater() that runs on the animation thread (you’re doing the opposite of what’s required putting it on the EDT!) You can do this yourself using a ConcurrentLinkedQueue<Runnable> and polling and running those at the beginning or end of draw().

Or, possibly better for your case, a ConcurrentLinkedQueue<OSCMessage>?

@GoToLoop suggestion of a boolean flag will work for limited use cases where you don’t care about message arguments or number of invocations, but it should be a volatile boolean