2

My question is: How do I access values from another thread?

I have two .java files, Main.java and TrackHands.java

Main.java

/**
 * This is the main class, it is used to start the program. The only use of this
 * is to make everything more organized.
 */
package Kinect;

//import processing.core.PApplet;
/**
 * @author Tony Nguyen <Tony.Nguyen@HvA.nl>
 *
 */
public class Main
{

    public static void main(String _args[])
    {  
        Thread trackHands = new Thread(new TrackHands());
        trackHands.start();
    }
}

TrackHands.java

/*
 * This uses the normal Java layout to track the user and prints out the coordinates of the left and right hand
 */
package Kinect;

import SimpleOpenNI.*;
import processing.core.PApplet;
import processing.core.PVector;

/**
 * @author Tony Nguyen <Tony.Nguyen@HvA.nl>
 * @version 1.0
 */
public class TrackHands extends PApplet implements Runnable
{

    private int handLeftX, handLeftY = 0; // Holds the coordinates of the left hand
    SimpleOpenNI kinect = new SimpleOpenNI(this); // kinect object

    /**
     * Constructor Takes no parameters
     */
    public TrackHands()
    {
    }

    /**
     * run This will be executed when the thread starts
     */
    @Override
    public void run()
    {
        IntVector userList = new IntVector(); // Make a vector of ints to store the list of users        
        PVector leftHand = new PVector(); // Make a vector to store the left hand
        PVector convertedLeftHand = new PVector();

        kinect.enableDepth();
        kinect.enableUser(SimpleOpenNI.SKEL_PROFILE_ALL);
        kinect.setMirror(true);

        while (true)
        {
            kinect.update();

            kinect.getUsers(userList); // Write the list of detected users into the vector

            if (userList.size() > 0) // Checks if a user is found
            {
                int userId = userList.get(0); // Get first user

                if (kinect.isTrackingSkeleton(userId)) // If successfully calibrated
                {
                    kinect.getJointPositionSkeleton(userId,
                            SimpleOpenNI.SKEL_LEFT_HAND, leftHand); // Put the position of the left hand into that vector

                    kinect.convertRealWorldToProjective(leftHand,
                            convertedLeftHand);

                    this.handLeftX = round(convertedLeftHand.x);
                    this.handLeftY = round(convertedLeftHand.y);
                }
            }
        }

    }

    // User-tracking callbacks!
    public void onNewUser(int userId)
    {
        System.out.println("Start pose detection");
        kinect.startPoseDetection("Psi", userId);
    }

    public void onEndCalibration(int userId, boolean successful)
    {
        if (successful)
        {
            System.out.println("  User calibrated !!!");
            kinect.startTrackingSkeleton(userId);

        } else
        {
            System.out.println("  Failed to calibrate user !!!");
            kinect.startPoseDetection("Psi", userId);
        }
    }

    public void onStartPose(String pose, int userId)
    {
        System.out.println("Started pose for user");
        kinect.stopPoseDetection(userId);
        kinect.requestCalibrationSkeleton(userId, true);
    }
}

I have tried to use a getter and a setter to get the values from TrackHands.java into another thread. Tried creating objects and passing the values as parameters, but then my program will not use these new values in the run() method.

Charles
  • 50,943
  • 13
  • 104
  • 142
iKaos
  • 29
  • 1
  • 4
  • if you google java.util.concurrent tutorial will get some good pointers http://docs.oracle.com/javase/tutorial/essential/concurrency/locksync.html you need at least synchronized keyword around the shared object or might get dirty reads – tgkprog Apr 13 '13 at 18:26

2 Answers2

2

To get values from TrackHands, use a get method that accesses an instance variable that is set in run()

class TrackHands {
    Object output;

    public void run() {
        while(true) {
            output = new Object();
        }
    }

    public Object getOutput() {
        return output;
    }
}

Pass TrackHands into your consumer object and use it to call get getOutput() method.

Passing values in is a bit trickier, because you might cause race condition. Try something like this

class TrackHands {
    Object input = null;
    public boolean setInput(Object input) {
        if(this.input == null) {
            this.input = input;
            return true;
        } else {
            return false;
        }
   }
}

When your run() method uses input, set it to null so that another thread can pass in another input. Your producer thread will use this loop to pass in input:

public void sendInput(TrackHands th, Object input) {
    boolean done = false;
    while(!done) {
        done = th.setInput(input);
    }
}

This will keep trying to pass in input until it succeeds.

setInput uses the synchronized keyword so that only one thread can call this method at once, otherwise you'll get a race condition.

Zim-Zam O'Pootertoot
  • 17,888
  • 4
  • 41
  • 69
  • should use the objects in java.util.concurrent to pass values between threads – tgkprog Apr 13 '13 at 18:22
  • Thank you guys very much for helping! The values I want to get from TrackHands are updating frequently and I only need the newest values (those are X and Y coordinates from your hands), so locks are not really needed in my opinion. Or do you recommend me using them anyway? The line 'Object output;' on the second line, do I have to make an Object object? Or is this only for demonstrating purposes? Because I do not really know how to give a values to the object so I can get it from another thread. – iKaos Apr 13 '13 at 20:04
  • If you only need the latest input then there's no need for a lock, and you can make the Object any type you want - that was just for demonstration purposes. – Zim-Zam O'Pootertoot Apr 13 '13 at 20:07
  • Could you help me a bit more? The only solution I can think of is to make an other class with two ints and a constructor that accepts two int parameters and initializes them to the two ints. Add a get method to the new class and call the get method in the class I want to use the input in. And make the object and pass the values to it. But I think there is a much easier and more logical solution I can not think of. – iKaos Apr 13 '13 at 20:14
  • Another option is to use two get methods, one per int. Or to use one get method that returns an int array / arraylist. – Zim-Zam O'Pootertoot Apr 13 '13 at 20:17
  • Should I make those get methods in TrackHands or in a new class (like I mentioned in my previous comment)? Because I tried to make a get method earlier in TrackHands and somehow it will not give me a correct value when called in another class. – iKaos Apr 13 '13 at 20:21
  • It looks like you're using floats/doubles, so that's your problem - these are not updated atomically, so your get method might retrieve them in an inconsistent state. Here is an AtomicFloat class you can use http://stackoverflow.com/questions/5505460/java-is-there-no-atomicfloat-or-atomicdouble – Zim-Zam O'Pootertoot Apr 13 '13 at 20:36
1

A friend of mine solved my problem.

I want to thank everyone for helping me!

Main.java

/**
 * This is the main class, it is used to start the program. The only use of this
 * is to make everything more organized.
 */
package Kinect;

//import processing.core.PApplet;
/**
 * @author Tony Nguyen <Tony.Nguyen@HvA.nl>
 *
 */
public class Main
{

    public static void main(String _args[])
    {
//        PApplet.main(new String[]
//                {
//                    Sensor.class.getName()
//                });

        ValueStore valueStore = new ValueStore(); // ADDED THIS LINE
        Thread trackHands = new Thread(new TrackHands(valueStore)); // ADDED THIS LINE
        trackHands.start();
    }
}

TrackHands.java

/*
 * This uses the normal Java layout to track the user and prints out the coordinates of the left and right hand
 */
package Kinect;

import SimpleOpenNI.*;
import processing.core.PApplet;
import processing.core.PVector;

/**
 * @author Tony Nguyen <Tony.Nguyen@HvA.nl>
 * @version 1.0
 */
public class TrackHands extends PApplet implements Runnable
{

    private int handLeftX, handLeftY, handRightX, handRightY = 0; // Holds the coordinates of the left hand
    SimpleOpenNI kinect = new SimpleOpenNI(this); // kinect object
    private ValueStore valuesStore; // ADDED THIS LINE

    /**
     * Constructor Takes no parameters
     */
    public TrackHands()
    {
    }

    public TrackHands(ValueStore valuesStore)
    {
        this.valuesStore = valuesStore;
    }

    /**
     * run This will be executed when the thread starts
     */
    @Override
    public void run()
    {
        IntVector userList = new IntVector(); // Make a vector of ints to store the list of users        
        PVector leftHand = new PVector(); // Make a vector to store the left hand
        PVector rightHand = new PVector(); // Make a vector to store the right hand
        PVector convertedLeftHand = new PVector(); // Make a vector to store the actual left hand
        PVector convertedRightHand = new PVector(); // Make a vector to store the actual right hand

        kinect.enableDepth();
        kinect.enableUser(SimpleOpenNI.SKEL_PROFILE_ALL);
        kinect.setMirror(true);

        while (true)
        {
            kinect.update();

            kinect.getUsers(userList); // Write the list of detected users into the vector

            if (userList.size() > 0) // Checks if a user is found
            {
                int userId = userList.get(0); // Get first user

                if (kinect.isTrackingSkeleton(userId)) // If successfully calibrated
                {
                    kinect.getJointPositionSkeleton(userId,
                            SimpleOpenNI.SKEL_LEFT_HAND, leftHand); // Put the position of the left hand into that vector

                    kinect.getJointPositionSkeleton(userId,
                            SimpleOpenNI.SKEL_RIGHT_HAND, rightHand); // Put the position of the left hand into that vector

                    kinect.convertRealWorldToProjective(leftHand,
                            convertedLeftHand);

                    kinect.convertRealWorldToProjective(rightHand,
                            convertedRightHand);

                    this.handLeftX = round(convertedLeftHand.x);
                    this.handLeftY = round(convertedLeftHand.y);
                    this.handRightX = round(convertedRightHand.x);
                    this.handRightY = round(convertedRightHand.y);

                    valuesStore.setHandValues(handLeftX, handLeftY, handRightX, handRightY); // ADDED THIS LINE
                }
            }
        }

    }

    // User-tracking callbacks!
    public void onNewUser(int userId)
    {
        System.out.println("Start pose detection");
        kinect.startPoseDetection("Psi", userId);
    }

    public void onEndCalibration(int userId, boolean successful)
    {
        if (successful)
        {
            System.out.println("  User calibrated !!!");
            kinect.startTrackingSkeleton(userId);

        } else
        {
            System.out.println("  Failed to calibrate user !!!");
            kinect.startPoseDetection("Psi", userId);
        }
    }

    public void onStartPose(String pose, int userId)
    {
        System.out.println("Started pose for user");
        kinect.stopPoseDetection(userId);
        kinect.requestCalibrationSkeleton(userId, true);
    }
}

Then added a class to store the values so another class can access it.

ValueStore.java

/*
 * To change this template, choose Tools | Templates
 * and open the template in the editor.
 */
package Kinect;

/**
 *
 * @author Tony Nguyen <Tony.Nguyen@HvA.nl>
 */
public class ValueStore
{

    private int leftX, leftY, rightX, rightY = 0;

    public void setHandValues(int leftX, int leftY, int rightX, int rightY)
    {
        this.leftX = leftX;
        this.leftY = leftY;
        this.rightX = rightX;
        this.rightY = rightY;
    }

    public int getLeftX()
    {
        return this.leftX;
    }
}
iKaos
  • 29
  • 1
  • 4