Reentrant lock - illegalmonitorstateexception when trying to write a byte[] to a serial port using rxtx

StackOverflow https://stackoverflow.com/questions/15769220

質問

I have the following code which is giving me a lot of trouble, I think I've been staring at it too long and fresh eyes would be appreciated -

Calling method - (in RobotInterface class)

        try
        {
            serialConnection.put(candidate.getCandidate().getGenome());
            TwoWaySerialCommTest.inputAvailable.await();
        }
        catch ( Exception e )
        {
            TwoWaySerialCommTest.listPorts();
            e.printStackTrace();
        }

TwoWaySerialCommTest class - adapted from rxtx website example. Full code for reference, the important parts are the put() method and the serialwriter.

     package org.dnsdojo.ryanhost.GA.MuPlusOne;

    import gnu.io.CommPort;
    import gnu.io.CommPortIdentifier;
    import gnu.io.SerialPort;
    import gnu.io.SerialPortEvent;
    import gnu.io.SerialPortEventListener;

    import java.io.IOException;
    import java.io.InputStream;
    import java.io.OutputStream;
    import java.util.concurrent.locks.*;

    /**
     * This version of the TwoWaySerialComm example makes use of the
     * SerialPortEventListener to avoid polling.
     *
     */
    public class TwoWaySerialCommTest
    {
            static Lock lock = new ReentrantLock();
            static Condition outputAvailable = lock.newCondition();
            static Condition inputAvailable = lock.newCondition();
            public volatile byte[] inputBuffer = new byte[1024];
            public volatile byte[] outputBuffer = new byte[1024];

            public TwoWaySerialCommTest()
        {
            super();
        }

            public void put(byte[] buffer)
            {
                    try
                    {
                            lock.lock();
                            int i = 0;
                            for(; i < buffer.length; i++ )
                            {
                                    outputBuffer[i] = buffer[i];
                            }
                            System.out.println((byte) '\n');
                            outputBuffer[i] = (byte) '\n';
                            i++;
                            for(; i < outputBuffer.length; i++ )
                            {
                                    outputBuffer[i] = 0;
                            }
                            System.out.println("Output buffer after put");
                            for(int j = 0; j < outputBuffer.length; j++)
                            {
                                    System.out.print(outputBuffer[j]);
                            }

                    }
                    catch(Exception e)
                    {
                            System.out.println("Exception for lock in put");
                            e.printStackTrace();
                    }
                    finally
                    {
                            lock.unlock();
                            outputAvailable.signal();
                    }
            }


        void connect ( String portName ) throws Exception
        {
            CommPortIdentifier portIdentifier = CommPortIdentifier.getPortIdentifier(portName);
            if ( portIdentifier.isCurrentlyOwned() )
            {
                System.out.println("Error: Port is currently in use");
            }
            else
            {
                CommPort commPort = portIdentifier.open(this.getClass().getName(),2000);

                if ( commPort instanceof SerialPort )
                {
                    SerialPort serialPort = (SerialPort) commPort;
                    serialPort.setSerialPortParams(57600,SerialPort.DATABITS_8,SerialPort.STOPBITS_1,SerialPort.PARITY_NONE);

                    InputStream in = serialPort.getInputStream();
                    OutputStream out = serialPort.getOutputStream();


                    serialPort.addEventListener(new SerialReader(in , inputBuffer));
                    serialPort.notifyOnDataAvailable(true);

                    (new Thread(new SerialWriter(out , outputBuffer))).start();

                }
                else
                {
                    System.out.println("Error: Only serial ports are handled by this example.");
                }
            }
        }

        static void listPorts()
        {
            java.util.Enumeration<CommPortIdentifier> portEnum = CommPortIdentifier.getPortIdentifiers();
            while(portEnum.hasMoreElements())
            {
                    CommPortIdentifier portIdentifier = portEnum.nextElement();
                    if(portIdentifier == null)
                    {
                            System.out.println("No ports");
                    }
                    System.out.println("Available - " + portIdentifier.getName());
            }
        }

        /**
         * Handles the input coming from the serial port. A new line character
         * is treated as the end of a block in this example.
         */
        public static class SerialReader implements SerialPortEventListener
        {
            private InputStream in;
            byte[] buffer;

            public SerialReader ( InputStream in )
            {
                this.in = in;
            }

            public SerialReader (InputStream in, byte[] buffer)
            {
                    this.in = in;
                    this.buffer = buffer;
            }

            public void serialEvent(SerialPortEvent arg0) {
                lock.lock();
                    int data;

                try
                {

                    int len = 0;
                    while ( ( data = in.read()) > -1 )
                    {
                        if ( data == '\n' )
                        {
                            break;
                        }
                        buffer[len++] = (byte) data;
                    }
                    //inputAvailable.signal();
                    //outputAvailable.signal();
                }
                catch ( IOException e )
                {
                    e.printStackTrace();
                    System.exit(-1);
                }
                finally
                {
                    lock.unlock();
                }
            }

        }

        /** */
        public static class SerialWriter implements Runnable
        {
            OutputStream out;
            volatile byte[] buffer;

            public SerialWriter ( OutputStream out )
            {
                this.out = out;
            }

            public SerialWriter ( OutputStream out, byte[] buffer)
            {
                    this.out = out;
                    this.buffer = buffer;
            }

            public void run ()
            {
                    while(true)
                    {
                            lock.lock();
                            try
                        {
                            outputAvailable.await();
                            System.out.println("Waking up");
                            int i = 0;
                            if (this.buffer != null)
                            {
                                    System.out.println("Buffer isn't empty");
                                    for (int j = 0; j < buffer.length; j++)
                                    {
                                            System.out.print(buffer[i]);
                                    }
                                    while(buffer[i] != ((byte)'\n') && i < buffer.length -1 )
                                    {
                                            this.out.write(buffer[i++]);
                                            System.out.print(buffer[i-1]);
                                            buffer[i-1] = 0;
                                    }
                            }
                            else
                            {
                                    System.out.println("Buffer is null");
                                    System.out.println(this.buffer.toString());
                            }
                        }
                        catch ( IOException e )
                        {
                            e.printStackTrace();
                            System.exit(-1);
                        }
                        catch(Exception e)
                        {
                            e.printStackTrace();
                        }

                            finally
                            {

                                    lock.unlock();
                            }
                    }
            }
        }



       /* public static void main ( String[] args )
        {
            try
            {
                (new TwoWaySerialCommTest()).connect("/dev/ttyS82");
            }
            catch ( Exception e )
            {
                TwoWaySerialCommTest.listPorts();
                e.printStackTrace();
            }
        }
*/

    }

The output is shown below. I've tried moving the lock files around, taking the lock out of the serial writer, putting a lock in the calling method and some other hacks.

The desired result is that the method will call the serialConnection(an instance of TwoWaySerialCommTest which has connected) , and wait for serialConnection to write to the serial port and receive a response before continuing execution.

I've been banging my head off this for hours now, please help :)

Output buffer after put
10101010000001101111010110101111010000100110101000000011101011100011000101111111010011101111001100111110001010011000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000RXTX fhs_lock() Error: creating lock file: /var/lock/LCK..ttyS82: File exists
java.lang.IllegalMonitorStateException
    at java.util.concurrent.locks.AbstractQueuedSynchronizer$ConditionObject.signal(AbstractQueuedSynchronizer.java:1941)
    at org.dnsdojo.ryanhost.GA.MuPlusOne.TwoWaySerialCommTest.put(TwoWaySerialCommTest.java:64)
    at org.dnsdojo.ryanhost.GA.MuPlusOne.RobotInterface.evaluate(RobotInterface.java:35)
    at org.dnsdojo.ryanhost.GA.MuPlusOne.RobotInterface.run(RobotInterface.java:58)
    at java.lang.Thread.run(Thread.java:722)

If I move the notify to within the try block as suggested the output is

Output buffer after put
    11100111000111010010111111000110100010010111000000110001010011001001110001010111110001010110010001010001010110101000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000Waking up
Buffer isn't empty
        1111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111RXTX fhs_lock() Error: creating lock file: /var/lock/LCK..ttyS82: File exists
1111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111110011100011101001011111100011010001001011100000011000101001100100111000101011111000101011001000101000101011010java.lang.IllegalMonitorStateException
    at java.util.concurrent.locks.ReentrantLock$Sync.tryRelease(ReentrantLock.java:155)
    at java.util.concurrent.locks.AbstractQueuedSynchronizer.release(AbstractQueuedSynchronizer.java:1260)
    at java.util.concurrent.locks.AbstractQueuedSynchronizer.fullyRelease(AbstractQueuedSynchronizer.java:1723)
    at java.util.concurrent.locks.AbstractQueuedSynchronizer$ConditionObject.await(AbstractQueuedSynchronizer.java:2040)
    at org.dnsdojo.ryanhost.GA.MuPlusOne.RobotInterface.evaluate(RobotInterface.java:36)
    at org.dnsdojo.ryanhost.GA.MuPlusOne.RobotInterface.run(RobotInterface.java:58)
    at java.lang.Thread.run(Thread.java:722)

The RobotInterface Class -

package org.dnsdojo.ryanhost.GA.MuPlusOne;

import org.apache.log4j.Logger;
import org.apache.log4j.PropertyConfigurator;

public class RobotInterface implements Runnable
{
    // create a serial connection
    // transmit a string and check for response
    // wait for evaluation
    // take evaluation
    private CandidateTest candidate;
    private TwoWaySerialCommTest serialConnection;
    //private Random rng = new Random();

    protected static Logger logger = Logger.getLogger("Thread" + Thread.currentThread().getName());

    public RobotInterface(CandidateTest test, TwoWaySerialCommTest serialConnection)
    {
            this.candidate = test;
            this.serialConnection = serialConnection;
            PropertyConfigurator.configure("log4j.properties");
    }

    public void evaluate (Genome genome)
    {
            //send to robot and return fitness
            //genome.setFitness(rng.nextDouble());
            logger.debug("fitness is " + genome.getFitness());
            try
            {
                    try
        {

            serialConnection.put(candidate.getCandidate().getGenome());
            TwoWaySerialCommTest.inputAvailable.await();


        }
        catch ( Exception e )
        {
            TwoWaySerialCommTest.listPorts();
            e.printStackTrace();
        }
            }
            catch(Exception E)
            {

            }

    }

    public void run()
    {
            logger.debug("entering run of Robot Interface");
            logger.debug("Send Genome via serial and wait for a response");
            Genome testSubject = candidate.getCandidate();
            evaluate(testSubject);
            candidate.finished();
    }

}

役に立ちましたか?

解決

You are calling signal AFTER you release the lock whereas you should call it WHILE holding the lock:

lock.unlock();
outputAvailable.signal();

should be the opposite:

outputAvailable.signal();
lock.unlock();

although it would be better practice to call signal at the end of the try block.

他のヒント

As per this link...
Before you use lock files you need to do one of two things:
Be user 'root' or user 'uucp' on your machine whenever you use RXTX .. or ..
Add the specific user that needs to use RXTX to the group 'uucp' (preferred)

ライセンス: CC-BY-SA帰属
所属していません StackOverflow
scroll top