We are about to switch to a new forum software. Until then we have removed the registration on this forum.
Can someone help me understand why this code:
import TUIO.*;
TuioProcessing tuioClient;
boolean ACTION;
void setup() {
tuioClient = new TuioProcessing(this);
ACTION = true;
}
void draw() {
while(ACTION) {};
println("I'm free!");
ACTION = true;
}
void addTuioObject(TuioObject tobj) {
println("Object added.");
ACTION = false;
}
Never prints "I'm free!", but manages to print "Object added." ?
Answers
Don't you realize that
while(ACTION) {};
besides being an infinite loop, is toasting our CPUs!! :-OAnother little nagging-> By convention, all cap names are reserved for constants. But ACTION is a variable! [-X
Now, even though draw() is stuck forever due to that infinite
while
, addTuioObject() still happensb/c it's called by a separate running Thread controlled by the TuioProcessing instance created at setup()!
A method which is supposed to be called automatically by some foreign
class
is nicked "callback" function.And for that external object instance to know which
class
a callback belongs to, it needs a reference from it.That's why you had to pass
this
as argument for the instantiation of TuioProcessing! :ar!An extra side note: setup(), draw(), and all of the event functions such as mouseMoved(), etc., are callback functions too!
They're overseered by a Thread called "Animation Thread". Which is instantiated at the very beginning when Processing starts!
To know more about what a Thread is, go to the link below:
docs.oracle.com/javase/6/docs/api/java/lang/Thread.html
And Processing got an unofficial simple way to invoke a method (which doesn't belong to another
class
)as a separate Thread by using thread("")!
I guess my question is how can I make
ACTION
a global variable, shared between the TuioProcessing and the Animation threads. That way the following code would break the while loop, no?Thanks for the advice with the variables convention. I'm assuming correctly that every
addTuioObject(TuioObject tobj)
generates a new TuioProcessing thread, correct?I remember I've faced that bug before when dealing w/ threads!
ACTION is a shared variable, accessed by both "Animation" & "TuioProcessing" threads!
But that infinite loop, which is being run by the animation thread, is accessing that shared variable like non-stop!
There's no time gap for the callback addTuioObject() to take control of the ACTION variable in order to change its value!!! b-(
I don't understand why you're halting the whole draw() w/ such a loop in the 1st place! :-q
And both threads are locked up b/c of that!!!
You may try to append a delay() for that
while
loop to create a time gap.But I don't see much logic doing so inside draw()!
Also, for
boolean
variables, names such as isBusy is much more in line to its meaning! (*)And of course, don't use all-caps names for non-constant variables! o->
A better attemp fix: (using actNow in place of ACTION)
Actually my real code is a bit more complex (I'm just trying to better understand which threads are running in the background of Processing, and how to make them share the
isBusy
variable in a friendly manner).I'm currently assuming that each new
addTuioObject(TuioObject tobj)
generates a new TuioProcessing thread. If so, and if I'm doing some operations withtobj
and arrays (e.g.example_array
) , I want to make sure that once I'm inside oneaddTuioObject(TuioObject tobj)
example_array
is locked:That's why I mention crude semaphores in the topic's title. My problem is that sometimes (feels pretty random), my code gets stuck in a
while (isBusy) {};
. I have a similar code in bothaddTuioObject(TuioObject tobj)
,updateTuioObject(TuioObject tobj)
, andremoveTuioObject(TuioObject tobj)
.Re-read what I've been saying about that! That's an infinite loop which doesn't do anything but locking up the conditional variable; plus spiking up CPU to new heights!
Open "Task Manager" or something similar and run this code and check for yourself:
Now, using delay() fixes CPU spike and frees up the conditional variable to be accessed somewhere else:
But in this case,
isBusy
is set as false by default. It's only turnedtrue
when aaddTuioObject(TuioObject tobj)
is running, to unsure no other threads alter crucial variables (e.g. arrays).I have code in Java with multiple threads that use similar synchronisation (with static variables being shared amongst threads). This is fairly common practice I believe.
But I guess a delay will have to do. Thanks for all the advice :)
To know that for sure, only by perusing that class source code or using some runtime analysis utility we would find that out! 8-X
But I myself would bet that the Thread calling back addTuioObject() is the very same TuioProcessing 1,
which is created internally at the moment of its instantiation within setup()!
At most, an extra Thread created by that same Thread! (~~)
As long as you don't lock-in a variable in closed-knit loops like
while (sharedVar);
, that strategy is valid for simple cases.AFAIK, advisable common practice is by issuing block locks (atomized blocks) using
synchronized
keyword:http://docs.oracle.com/javase/tutorial/essential/concurrency/locksync.html
What you're doing is creating your own custom semaphore, which is generally faster than using
synchronized
. :-jCrude is the operative word :D