java应用程序中通过RxTx从两个串行端口并发读取的问题 关于我的问题的一些背景
我有一个从两个串行端口读取数据的应用程序。这些串行端口在我工作的公司定制的两个硬件之间接入消息。一个串行端口接入从硬件A到硬件B的消息,而另一个端口在另一个方向上传输消息。我需要读取、解析和显示这些消息,以帮助调试我们在明显删除和重复消息时遇到的问题最重要的是,我的应用程序必须在消息发送时显示消息(即,按照发送顺序和发送次数),并带有正确的时间戳。 我的应用程序是用java编写的,通过RxTx和串行端口接口。我一直在64位Windows 7 PC上运行我的应用程序 绝大多数(双向)发送的消息都是请求和确认(这些请求的确认)。每个请求消息包含一个序列号,相应的ACK将包含相同的序列号。当系统不忙时,我的程序似乎工作得近乎完美。但是,当消息开始很快出现时,我的程序会遇到问题 我遇到的问题是,我的应用程序似乎从一个串行端口读取多条消息,然后从另一个端口读取,而不是几乎同时从两个端口读取 我的应用程序的核心使用5个线程。其中两个读卡器只从端口读取一个字节,然后将该字节放入队列。每个队列都与另一个线程共享,该线程将这些字节解析为消息。(因此有两个处理线程,每个读卡器一个)。然后,这两个处理线程将这些已解析的消息放入另一个队列。第五个线程管理这些消息的显示,然后从该队列获取消息 (上面未提及的是我的GUI,它通过EDT运行) 在我看来,问题似乎在于(或可能在之前)读线程,它似乎与并发性或共享CPU时间片有关。我只是不知道这种阻塞是发生在操作系统级别(操作系统从一个端口读取而不是从另一个端口读取)、RxTx级别还是我的代码中 我的读者线程代码在这个问题的底部 我的理由是:java应用程序中通过RxTx从两个串行端口并发读取的问题 关于我的问题的一些背景,java,multithreading,serial-port,rxtx,serial-communication,Java,Multithreading,Serial Port,Rxtx,Serial Communication,我有一个从两个串行端口读取数据的应用程序。这些串行端口在我工作的公司定制的两个硬件之间接入消息。一个串行端口接入从硬件A到硬件B的消息,而另一个端口在另一个方向上传输消息。我需要读取、解析和显示这些消息,以帮助调试我们在明显删除和重复消息时遇到的问题最重要的是,我的应用程序必须在消息发送时显示消息(即,按照发送顺序和发送次数),并带有正确的时间戳。 我的应用程序是用java编写的,通过RxTx和串行端口接口。我一直在64位Windows 7 PC上运行我的应用程序 绝大多数(双向)发送的消息都是
thread.yield()
,端口A读取器线程似乎从未向端口B读取器线程屈服(如本问题底部的读者线程代码所示)。为了举例说明,我看到了如下消息序列:
[From Hardware A, To Hardware B] [Timestamp: 0 us] Request for 0x01
[From Hardware A, To Hardware B] [Timestamp: 60 us] ACK for 0x02
[From Hardware A, To Hardware B] [Timestamp: 120 us] ACK for 0x03
[From Hardware B, To Hardware A] [Timestamp: 180 us] ACK for 0x01
[From Hardware B, To Hardware A] [Timestamp: 240 us] Request for 0x02
[From Hardware B, To Hardware A] [Timestamp: 300 us] Request for 0x03
[From Hardware A, To Hardware B] [Timestamp: 0 us] Request for 0x01
[From Hardware B, To Hardware A] [Timestamp: 60 us] ACK for 0x01
[From Hardware B, To Hardware A] [Timestamp: 120 us] Request for 0x02
[From Hardware A, To Hardware B] [Timestamp: 180 us] ACK for 0x02
[From Hardware B, To Hardware A] [Timestamp: 240 us] Request for 0x03
[From Hardware A, To Hardware B] [Timestamp: 300 us] ACK for 0x03
但我希望这些信息会像这样到达:
[From Hardware A, To Hardware B] [Timestamp: 0 us] Request for 0x01
[From Hardware A, To Hardware B] [Timestamp: 60 us] ACK for 0x02
[From Hardware A, To Hardware B] [Timestamp: 120 us] ACK for 0x03
[From Hardware B, To Hardware A] [Timestamp: 180 us] ACK for 0x01
[From Hardware B, To Hardware A] [Timestamp: 240 us] Request for 0x02
[From Hardware B, To Hardware A] [Timestamp: 300 us] Request for 0x03
[From Hardware A, To Hardware B] [Timestamp: 0 us] Request for 0x01
[From Hardware B, To Hardware A] [Timestamp: 60 us] ACK for 0x01
[From Hardware B, To Hardware A] [Timestamp: 120 us] Request for 0x02
[From Hardware A, To Hardware B] [Timestamp: 180 us] ACK for 0x02
[From Hardware B, To Hardware A] [Timestamp: 240 us] Request for 0x03
[From Hardware A, To Hardware B] [Timestamp: 300 us] ACK for 0x03
public static final long BYTE_MASK = 0x7F80000000000000L;
public static final int BYTE_SHIFT = 55;
public static final long TIMESTAMP_MASK = 0x007FFFFFFFFFFFFFL;
public static final long TIMESTAMP_SHIFT = 0;
comOneReader = new SerialPortReader(commInput[0],
comOneInputByteQueue);
comTwoReader = new SerialPortReader(commInput[1],
comTwoInputByteQueue);
Thread comOne = new Thread(comOneReader, "COM1 Reader");
Thread comTwo = new Thread(comTwoReader, "COM2 Reader");
comOne.setPriority(Thread.MAX_PRIORITY);
comTwo.setPriority(Thread.MAX_PRIORITY);
comOne.start();
comTwo.start();
创建SerialPort
s及其相应的InputStream
s.COMM\u PORT\u ID
是我所需COM端口的CommPortIdentifier
对象数组。SerialPort
是所需COM端口的SerialPort
对象数组。commInput
是用于所需COM端口的InputStream
对象数组。所有这些都发生在包含类中
for (int i = 0; i < 2; i++)
{
serialPorts[i] = (SerialPort) COMM_PORT_ID[i].open("SERIAL CONNECTION", 2000);
serialPorts[i].setSerialPortParams(BAUD_RATE, DATA_BITS, STOP_BITS, PARITY);
serialPorts[i].setFlowControlMode(SerialPort.FLOWCONTROL_NONE);
serialPorts[i].enableReceiveTimeout(1000);
serialPorts[i].setInputBufferSize(3);
serialPorts[i].disableReceiveThreshold();
serialPorts[i].notifyOnDataAvailable(false);
serialPorts[i].notifyOnFramingError(true);
serialPorts[i].notifyOnOutputEmpty(false);
serialPorts[i].notifyOnOverrunError(true);
commInput[i] = serialPorts[i].getInputStream();
}
读者自己:
private class SerialPortReader implements Runnable
{
private final long startSystemTime;
private final long startNano;
private final InputStream input;
private AtomicBoolean reading; // used to stop and start the reading of bytes
private final LinkedTransferQueue<Long> toProcessorByteQueue;
private long holder;
public SerialPortReader(InputStream input,
LinkedTransferQueue<Long> toProcessorByteQueue)
{
this.input = input;
this.toProcessorByteQueue = toProcessorByteQueue;
reading = new AtomicBoolean();
startSystemTime = System.currentTimeMillis();
startNano = System.nanoTime();
}
@Override
public void run()
{
long in = -1;
reading.set(true);
while (reading.get())
{
try
{
in = -1;
// Read the next byte from the serial port, blocking until one is available
if ((in = input.read()) != -1)
{
// I store the byte and a timestamp (in microseconds) in a long
// Skipping bit 63 (the sign bit), I will store the byte from the serial read
// in bits 62 - 55. Then the remainder (bits 54-0) will be the timestamp
holder = ((in & 0xFF)) << BYTE_SHIFT;
holder |= ((startSystemTime * 1000L) + ((System.nanoTime() - startNano) / 1000L)) & TIMESTAMP_MASK;
// Add the long to the queue
toProcessorByteQueue.add(holder);
}
Thread.yield();
}
catch (IOException ioe)
{
// Deal with Exception
}
}
}
public void stop()
{
reading.set(false);
}
}
私有类SerialPortReader实现可运行
{
专用最终长启动系统时间;
私人决赛长startNano;
私有最终输入流输入;
private AtomicBoolean reading;//用于停止和开始读取字节
私有最终链接传输队列到ProcessorByteQueue;
私人多头持有人;
公共SerialPortReader(InputStream输入,