【发布时间】:2019-02-21 07:24:26
【问题描述】:
我有一个处理串行端口的小型 android 库,它具有打开、读取、写入和关闭等基本功能。
我做了一个应用程序,使用这个库在串口上写入并读取响应,在这个应用程序中有一个线程定期打开串口询问状态获取响应并关闭串口。
我想保护串行通信,如果主线程打开通信,只检查状态的辅助线程不能打开它并等待主线程完成。
class SerialChannel extends Channel
{
private SerialPortUtility serialPortUtility;
private static final String SERIAL_FILE = "/dev/ttyMT2";
private static final String CONTROL_FILE = "/sys/devices/platform/file";
private static final String UNKNOWN_COMMAND = "UNKNOWN COMMAND";
private FileOutputStream fileOutputStream;
private FileInputStream fileInputStream;
@Override
public void open() throws CommunicationException
{
try
{
if (isSerialOpened() != SerialStatus.Open)
{
toggleSerial(SerialStatus.Open.getStatus());
Thread.sleep(100);
}
serialPortUtility = getSerialPortUtility();
fileInputStream = (FileInputStream) serialPortUtility.getInputStream();
fileOutputStream = (FileOutputStream) serialPortUtility.getOutputStream();
currentProcess = Optional.of(Thread.currentThread().getId());
Thread.sleep(500);
}
catch (IOException | InterruptedException e)
{
throw new CommunicationException(e.getMessage());
}
}
@Override
public void close() throws CommunicationException
{
if (serialPortUtility == null)
{
throw new CommunicationException("SerialPort is null");
}
try
{
toggleSerial(SerialStatus.Close.getStatus());
fileOutputStream.close();
fileInputStream.close();
serialPortUtility.close();
fileInputStream = null;
fileOutputStream = null;
serialPortUtility = null;
}
catch (IOException e)
{
throw new CommunicationException(e.getMessage());
}
}
@Override
public void send(byte[] buffer, int timeout, int length) throws CommunicationException
{
if (fileOutputStream == null)
{
throw new CommunicationException("Problem while sending data!");
}
try
{
fileOutputStream.write(buffer);
fileOutputStream.flush();
}
catch (IOException e)
{
throw new CommunicationException(e.getMessage());
}
}
@Override
public byte[] receive(int length, int timeout) throws CommunicationException
{
StringBuilder stringBuilder = new StringBuilder();
byte[] buffer = new byte[length];
int ret;
int totalSize = 0;
if (fileInputStream == null)
{
throw new CommunicationException("FileInputStream is null!");
}
try
{
long millisStart = Calendar.getInstance().getTimeInMillis();
boolean timeoutReached;
while (true)
{
timeoutReached = (Calendar.getInstance().getTimeInMillis() - millisStart > timeout * 1000);
if (fileInputStream.available() <= 0 && timeoutReached)
{
expectingResult = false;
throw new CommunicationException("Error");
}
else if (fileInputStream.available() > 0)
{
break;
}
}
millisStart = Calendar.getInstance().getTimeInMillis();
while (totalSize != length && (ret = fileInputStream.read(buffer)) != -1)
{
String received = new String(buffer);
stringBuilder.append(received);
if(buffer.length == 15 && received.equals(UNKNOWN_COMMAND))
{
break;
}
totalSize += ret;
}
expectingResult = false;
}
catch (IOException e)
{
throw new CommunicationException(e.getMessage());
}
return stringBuilder.toString().getBytes();
}
private SerialPortUtility getSerialPortUtility() throws IOException
{
if (serialPortUtility == null)
{
File file = new File(SERIAL_FILE);
int baudRate = 115200;
return new SerialPortUtility(file, baudRate, 0);
}
return serialPortUtility;
}
private void toggleSerial(String data) throws IOException
{
FileOutputStream fos = new FileOutputStream(new File(CONTROL_FILE));
fos.write(data.getBytes());
fos.flush();
fos.close();
}
private SerialStatus isSerialOpened() throws IOException
{
byte[] buffer = new byte[1];
FileInputStream fis = new FileInputStream(new File(CONTROL_FILE));
int result = fis.read(buffer);
fis.close();
if (result > -1 && buffer[0] == 1)
{
return SerialStatus.Open;
}
return SerialStatus.Close;
}
}
这个类扩展了自定义类 Channel,它实现了一个带有方法 open、close、read、send 的接口,还实现了 AutoCloseable。
现在,如果我使 open 方法同步,任何进入这里的线程都会锁定,但会锁定直到它退出 open 方法,当线程移动到另一个方法时,让我们说 read 并留在那里直到它得到响应,检查器线程会来并进入 open 方法。使用 AutoCloseable,close 方法将执行并关闭串口通信。如果我同步一个对象,对象不同步的时候还是有窗口的。
如何告诉checker线程通信已经打开,让他等到主线程结束。
Checker 看起来像这样,它在一个计时器内:
try(Channel ch = CommunicationFactory.getInstance().selectChannel(CommunicationType.SERIAL))
{
ch.open();
//do stuff
}
catch (CommunicationException ex)
{
ex.printStackTrace();
}
“主”线程看起来与 AysncTask 中的相同。
如果需要其他信息,请告诉我!
提前感谢您的努力和时间!
【问题讨论】:
标签: java android multithreading