当使用rxtx尝试将字节[]写入串行端口时,可重入锁定 - illegalmonitorstateexception

时间:2013-04-02 16:23:14

标签: java concurrency locking rxtx reentrantlock

我有以下代码给我带来了很多麻烦,我想我已经盯着它看了太长时间,新鲜的眼睛会受到赞赏 -

调用方法 - (在RobotInterface类中)

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

TwoWaySerialCommTest类 - 改编自rxtx网站示例。完整代码供参考,重要的部分是put()方法和序列编写器。

     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();
            }
        }
*/

    }

输出如下所示。我已经尝试移动锁定文件,将锁定从串行编写器中取出,锁定调用方法和其他一些黑客攻击。

期望的结果是该方法将调用serialConnection(已连接的TwoWaySerialCommTest的实例),并等待serialConnection写入串行端口并在继续执行之前接收响应。

我现在已经开了几个小时了,请帮忙:)。

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)

如果我按照建议将输出移动到try块内,则输出为

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)

RobotInterface类 -

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();
    }

}

2 个答案:

答案 0 :(得分:2)

您在释放锁定后调用signalyou should call it WHILE holding the lock

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

应该是相反的:

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

虽然最好在signal块的末尾调用try

答案 1 :(得分:0)

As per this link...
在使用锁定文件之前,您需要执行以下两项操作之一:
无论何时使用RXTX,都要在机器上使用“root”或用户“uucp” ..或..
将需要使用RXTX的特定用户添加到'uucp'组(首选)