How to implement a crude semaphore to use with, e.g., TUIO

edited November 2013 in Library Questions

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

Tagged:

Answers

  • edited November 2013

    Don't you realize that while(ACTION) {}; besides being an infinite loop, is toasting our CPUs!! :-O
    Another 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 happens
    b/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("")!

  • edited November 2013

    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?

    void addTuioObject(TuioObject tobj) {
      println("Object added.");
      ACTION = false;
    }
    

    Thanks for the advice with the variables convention. I'm assuming correctly that every addTuioObject(TuioObject tobj) generates a new TuioProcessing thread, correct?

  • edited November 2013

    Don't you realize that while(ACTION) {}; besides being an infinite loop, is toasting our CPUs!!

    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)

    import TUIO.*;
    TuioProcessing tuioClient;
    
    boolean actNow;
    
    void setup() {
      tuioClient  = new TuioProcessing(this);
    }
    
    void draw() {
      if (actNow) {
        println("I'm free!");
        actNow = false;
      }
    }
    
    void addTuioObject(TuioObject tobj) {
      println("Object added...");
      actNow = true;
    }
    
  • edited November 2013

    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 with tobj and arrays (e.g. example_array) , I want to make sure that once I'm inside one addTuioObject(TuioObject tobj) example_array is locked:

    void addTuioObject(TuioObject tobj) {
      while (isBusy) {};
      isBusy = true; 
      // (...) some actions with, e.g., example_array
      isBusy = false;
    }
    

    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 both addTuioObject(TuioObject tobj), updateTuioObject(TuioObject tobj), and removeTuioObject(TuioObject tobj).

  • edited November 2013

    my code gets stuck in a while (isBusy) {};.

    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:

    boolean isBusy = true;
    while (isBusy);
    

    Now, using delay() fixes CPU spike and frees up the conditional variable to be accessed somewhere else:

    boolean isBusy = true;
    while (isBusy)   delay(100);
    
  • edited November 2013

    But in this case, isBusy is set as false by default. It's only turned true when a addTuioObject(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 :)

  • edited November 2013

    I'm currently assuming that each new addTuioObject(TuioObject tobj) generates a new TuioProcessing thread.

    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! (~~)

  • edited November 2013 Answer ✓

    I have code in Java with multiple threads that use similar synchronization (with static variables being shared amongst threads).

    As long as you don't lock-in a variable in closed-knit loops like while (sharedVar);, that strategy is valid for simple cases.

    This is fairly common practice I believe.

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

  • Crude is the operative word :D

Sign In or Register to comment.