I'm writing a simple app that constantly reads some data from serial port over bluetooth and then draws that data on 2 charts. I came up with an idea of buffering that data to byte buffer and then reading it from some other part of the code. The problem is that I have to read that data quite frequently (reading only 5 bytes at once) and I have some issues with synchronization of the threads. The serial port reading part is not allowing the printing thread to read anything most of the time. Sometimes it gets through and prints some data. These 2 are the only threads that use buffer as the locking object.
I think I might've missunderstood some basic synchronization principles, but I'm starting to run out of ideas how can I solve this issue.
Reading from serial port part:
public void startReading() {
Thread thread = new Thread(new Runnable() {
#Override
public void run() {
resetBuffer();
read = true;
try {
serialPort.purgePort(SerialPort.PURGE_RXCLEAR);
byte[] buf = new byte[5];
int bytes;
while (read) {
synchronized (buffer) {
try {
bytes = inputStream.blockingRead(buf);
System.out.println(buf);
System.arraycopy(buf, 0, buffer, bufferPos, bytes);
bufferPos += buf.length;
buffer.notifyAll();
} catch (Exception e) {
e.printStackTrace();
}
}
}
} catch (SerialPortException e) {
e.printStackTrace();
}
}
});
thread.start();
}
Printing data part (in loop):
synchronized (buffer) {
while (serialPortConnection.getBufferLength() < 5) {
try {
buffer.wait();
} catch (Exception e) {
e.printStackTrace();
}
}
}
readBytesToStringBuffer();
printLineIfAvailable();
while (read) {
synchronized (buffer) {
try {
bytes = inputStream.blockingRead(buf);
Your problem is not in reading often; it is in blocking. You acquire the monitor on buffer and then enter a blocking I/O call. You spend precious little time outside of that call, thus outside of the synchronized block.
Advice:
First read from port outside of synchronized, then acquire the monitor to transfer the data to a shared structure.
Related
I have a thread handling a socket connection:
BufferedReader socketInput = new BufferedReader(new InputStreamReader(mySocket.getInputStream()));
while (true)
{
String line = socketInput.readLine();
// do stuff
}
As I've read in a few answers on this site, the recommended solution is to use a flag which one thread sets and my (socket handling) thread checks and terminates itself when that flag changes state. Something like:
while (!done)
{
String line = socketInput.readLine();
// do stuff
}
But this can get stuck when readLine() is still waiting for input. I guess I could set a timeout:
mySocket.setSoTimeout(100);
while (!done)
{
String line = socketInput.readLine();
// do stuff
}
Which would probably work but I would still get a 100 ms delay before my thread "realizes" the flag's state changed.
Is there a way for the thread to "realize" right away that it should end? If not, is my solution (with timeout and flag done) correct?
Edit: I've clarified that the socketInput is of type BufferedReader (alternatively I'm considering Scanner).
The most common way to handle this is to close the socket from the other Thread. This will lead the reading side to unblock and exit with the (expected) error that the socket was closed. Depending on the socket API that you have available it might also be possible to shutdown only the reading side. From a short look at the JDK shutdownInput() might work.
If you however want to continue to read from the socket later on these obvisouly won't work. Your solution should work there, but is obvisouly worse for performance and reactivity since you basically poll the socket all 100ms.
Create a Selector
Configure your socket.getChannel() to non-blocking and register it to the Selector with SelectionKey.OP_READ
Call your Selector select() method that will return when there are some data to read so you can call readLine() (i.e. select() returns > 0)
Whenever you want to end your socket processing, set your done flag and call your Selector wakeup() method. That will make the select() return immediately (potentially 0, or 1 if there was activity). You can then check your done flag and end your thread gracefully.
Here is a quick implementation. Notice I pass the BufferedReader as an argument as if you're opening it in the thread you should also close it there, which would close the socket too, so it has to be done outside. There are two methods to signal the thread to gracefully stop processing input and one to send data:
public class SocketHandler extends Thread {
private Socket sok;
private BufferedReader socketInput;
private Selector sel;
private SocketChannel chan;
private boolean done;
public SocketHandler(Socket sok, BufferedReader socketInput) throws IOException {
this.sok = sok;
chan = sok.getChannel();
chan.configureBlocking(false);
sel = Selector.open();
chan.register(sel, SelectionKey.OP_READ);
this.socketInput = socketInput;
done = false;
}
#Override
public void run() {
while (!done) {
try {
if (sel.select() == 0)
continue;
} catch (IOException e) {
e.printStackTrace();
}
// Only one channel is registered on only one operation so we know exactly what happened.
sel.selectedKeys().clear();
doRead();
// Otherwise: loop through sel.selectedKeys(), check for readability and clear the set
}
try {
sel.close();
} catch (IOException e) {
e.printStackTrace();
}
}
private void doRead() {
try {
String line = socketInput.readLine();
// TODO: process 'line'
} catch (IOException e) {
e.printStackTrace();
}
}
public void signalStop() {
done = true;
if (sel != null)
sel.wakeup(); // Get out of sel.select()
}
public void doWrite(byte[] buffer) throws IOException { // Or "String message"
sok.getOutputStream().write(buffer); // Or anything else
}
}
The solution is correct, it will exit when done is set to true.
And yes, the readLine will always wait for 100ms, if you don't want to wait you may interrupt the thread by calling thread.interrupt() it but it's not very clean way.
The best way to know when finish a socket connection is to try to read something. If read method return -1 you can end threadling socket connection
byte[] data = new byte[2048];
while (!done) {
int count = input.read(data);
if (count <= 0) {
if (count < 0)
done = true;
continue;
}
String request = new String(data, 0, count);
//do stuff
}
We try to read something in input if count == -1, the socket client is disconnected now we can end the loop, by changing the value of done.
I'm extending the BaseIOIOLooper to open up a UART device and send messages. I'm testing with a readback, where I send a packet over a line and receive that packet on another line and print it out. Because I don't want the InputStream.read() method to block, I am handling packet formation and input in a different thread. I have narrowed my problem down to the InputStream.read() method, which returns -1 (no bytes read, but no exception).
Here is what it looks like in the Looper thread:
#Override
protected void setup() throws ConnectionLostException, InterruptedException {
log_.write_log_line(log_header_ + "Beginning IOIO setup.");
// Initialize IOIO UART pins
// Input at pin 1, output at pin 2
try {
inQueue_ = MinMaxPriorityQueue.orderedBy(new ComparePackets())
.maximumSize(QUEUESIZE).create();
outQueue_ = MinMaxPriorityQueue.orderedBy(new ComparePackets())
.maximumSize(QUEUESIZE).create();
ioio_.waitForConnect();
uart_ = ioio_.openUart(1, 2, 38400, Uart.Parity.NONE, Uart.StopBits.ONE);
// Start InputHandler. Takes packets from ELKA on inQueue_
in_= new InputHandler(inQueue_, uart_.getInputStream());
in_.start();
// Start OutputHandler. Takes packets from subprocesses on outQueue_
out_= new OutputHandler(outQueue_);
out_.start();
// Get output stream
os_=uart_.getOutputStream();
// Set default target state
setTargetState(State.TRANSFERRING);
currInPacket_[0]=1; //Initial value to start transferring
log_.write_log_line(log_header_ + "IOIO setup complete.\n\t" +
"Input pin set to 1\n\tOutput pin set to 2\n\tBaud rate set to 38400\n\t" +
"Parity set to even\n\tStop bits set to 1");
} catch (IncompatibilityException e) {
log_.write_log_line(log_header_+e.toString());
} catch (ConnectionLostException e) {
log_.write_log_line(log_header_+e.toString());
} catch (Exception e) {
log_.write_log_line(log_header_+"mystery exception: "+e.toString());
}
}
And in the InputHandler thread:
#Override
public void run() {
boolean notRead;
byte i;
log_.write_log_line(log_header_+"Beginning InputHandler thread");
while (!stop) {
i = 0;
notRead = true;
nextInPacket = new byte[BUFFERSIZE];
readBytes = -1;
//StringBuilder s=new StringBuilder();
//TODO re-implement this with signals
while (i < READATTEMPTS && notRead) {
try {
// Make sure to adjust packet size. Done manually here for speed.
readBytes = is_.read(nextInPacket, 0, BUFFERSIZE);
/* Debugging
for (int j=0;j<nextInPacket.length;j++)
s.append(Byte.toString(nextInPacket[j]));
log_.write_log_line(log_header_+s.toString());
*/
if (readBytes != -1) {
notRead = false;
nextInPacket= new byte[]{1,0,1,0,1,0,1,0,1,0,1,0,1,0,1,0};
synchronized (q_) {
q_.add(nextInPacket);
}
//log_.write_log_line(log_header_ + "Incoming packet contains valid data.");
} else i++;
} catch (IOException e) {
log_.write_log_line(log_header_ + "mystery exception:\n\t" + e.toString());
}
}
if (i>=READATTEMPTS)
log_.write_log_line(log_header_+"Too many read attempts from input stream.");
/*
try {
sleep(100);
} catch (InterruptedException e) {
log_.write_log_line(log_header_+"fuck");
}
*/
}
}
On an oscilloscope, pins 1 and 2 both read an oscillating voltage, albeit at a very high amplitude, which is of some concern. Point is nothing is available to be read from the InputStream in the InputHandler class. Any ideas?
-1 returned from read() should only happen whenever the UART is closed. The closure can happen as result of explicitly calling close() on the Uart object or calling softReset() on the IOIO object.
The Android log might give you some clues about what's going on.
The reading you're seeing on the oscilloscope is suspicious: how high is "very high amplitude"? You should only ever see 0V or 3.3V on those pins, or floating in case the pins where not opened (or closed) for some reason.
I'm having a problem where I have a class that gets instantiated upon a connection to server.
The method I'm having trouble with in the class looks like so:
public void sendData(byte[] dataToSend) throws IOException {
sendLock.lock();
int dataLength = dataToSend.length;
dout.writeInt(dataLength);
dout.write(dataToSend, 0, dataLength);
dout.flush();
sendLock.unlock();
}
Where sendLock is a ReentrantLock and dout = new DataOutputStream(socket.getOutputStream());. This will work fine with a limited number of threads, but if I have a large number of threads calling this method concurrently I get a deadlock and the program just stops.
Is there any reason a deadlock would be happening here? It doesn't make sense to me, as I've removed all other locks to rule them out and I'm down to this one. Is there anyway the flush could cause things to hang or something? It just seems like at some point it never releases the lock and I'm not sure why.
If I remove the lock I get socket errors because one thread may change the dataLength before another has a chance to write, etc. But the deadlock no longer occurs.
As a reference, here's what the run method of the Receive end looks like:
public void run() {
while (socket != null) {
try {
int dataLength = din.readInt();
byte[] data = new byte[dataLength];
din.readFully(data, 0, dataLength);
Event e = ef.getEvent(data);
node.onEvent(e);
} catch (SocketException se) {
System.out.println(se.getMessage());
break;
} catch (IOException ioe) {
System.out.println(ioe.getMessage()) ;
break;
}
}
}
It's possible that one of your calls to the output stream throws an exception and sendLock.unlock() is never called. All the other threads will be left waiting forever.
Check your logs to see if one of the threads throws an exception. In your code I would use a try-catch-finally block instead of throwing IOException. This guarantees, even if something bad happens, the lock will be released so other threads can keep working.
public void sendData(byte[] dataToSend) throws IOException {
try {
sendLock.lock();
int dataLength = dataToSend.length;
dout.writeInt(dataLength);
dout.write(dataToSend, 0, dataLength);
dout.flush();
}
finally {
sendLock.unlock();
}
}
Basically the server side sends a keep alive message every 8 minutes, if the write fails it disconnects the client and closes the socket connection. If my android device is awake and the server closes the connection then the read operation on the android device throws an exception as it should and i disconnect from the server. If the device is asleep it doesn't read data at all even with a partial wake lock and a wifilock, i have already given up on that, but my actual problem is when my device comes back from sleep (if i turn the screen on for example) what i do is send a message to the server so i can refresh the data but if my server has already closed the socket my write operation should throw an IOException but for some reason it doesn't. And even the blocking read i have doesn't throw any exception or return -1.
here is my write operation:
public boolean sendData(byte[] data)
{
boolean sent=false;
if(connectedToServer)
{
try
{
myOutputStream.write(data, 0, data.length);
sent= true;
}
catch (IOException e)
{
e.printStackTrace();
unexpectedDisconnectionFromServer();
}
}
return sent;
}
and here is my read operation:
public void startReadingInBackground()
{
while(connectedToServer)
{
try
{
int bytesRead=0;
if(myWifiLock!=null && !myWifiLock.isHeld())
myWifiLock.acquire();
byte val=(byte)myInputStream.read();
myWakeLock.acquire();
if(val==-1)
{
unexpectedDisconnectionFromServer();
if(myWifiLock!=null && myWifiLock.isHeld())
myWifiLock.release();
myWakeLock.release();
return;
}
bytesRead=myInputStream.read(myBuffer, 0, bufferSize);
if(bytesRead<1)
{
unexpectedDisconnectionFromServer();
if(myWifiLock!=null && myWifiLock.isHeld())
myWifiLock.release();
myWakeLock.release();
return;
}
byte[] dataArray=Arrays.copyOfRange(myBuffer,0,bytesRead);
ByteBuffer data=ByteBuffer.allocate(bytesRead+1).put(val).put(dataArray);
myParent.invokeReceiveAction(data, bytesRead + 1);
}
catch (IOException e)
{
if(!myWakeLock.isHeld())
myWakeLock.acquire();
unexpectedDisconnectionFromServer();
e.printStackTrace();
}
finally
{
if(myWifiLock!=null && myWifiLock.isHeld())
myWifiLock.release();
if(myWakeLock!=null && myWakeLock.isHeld())
myWakeLock.release();
}
}
}
and i get the outputstream like so:
Socket mySocket = new Socket(SERVER_IP, SERVER_PORT_TCP );
myOutputStream=mySocket.getOutputStream();
Your write will throw an IOException, eventually. Your mistake is in assuming it is bound to happen on the first write after the disconnect. It won't, for all sorts of reasons including buffering and retries. TCP has to determine that the connection is really dead before it will reject a new write, and it certainly won't do that on the first write after the disconnect.
How do you design a read and write loop which operates on a single socket (which supports parallel read and write operations)? Do I have to use multiple threads? Is my (java) solution any good? What about that sleep command? How do you use that within such a loop?
I'm trying to use 2 Threads:
Read
public void run() {
InputStream clientInput;
ByteArrayOutputStream byteBuffer;
BufferedInputStream bufferedInputStream;
byte[] data;
String dataString;
int lastByte;
try {
clientInput = clientSocket.getInputStream();
byteBuffer = new ByteArrayOutputStream();
bufferedInputStream = new BufferedInputStream(clientInput);
while(isRunning) {
while ((lastByte = bufferedInputStream.read()) > 0) {
byteBuffer.write(lastByte);
}
data = byteBuffer.toByteArray();
dataString = new String(data);
byteBuffer.reset();
}
} catch (IOException e) {
e.printStackTrace();
}
}
Write
public void run() {
OutputStream clientOutput;
byte[] data;
String dataString;
try {
clientOutput = clientSocket.getOutputStream();
while(isOpen) {
if(!commandQueue.isEmpty()) {
dataString = commandQueue.poll();
data = dataString.getBytes();
clientOutput.write(data);
}
Thread.sleep(1000);
}
clientOutput.close();
}
catch (IOException e) {
e.printStackTrace();
}
catch (InterruptedException e) {
e.printStackTrace();
}
}
Read fails to deliver a proper result, since there is no -1 sent.
How do I solve this issue?
Is this sleep / write loop a good solution?
There are basically three ways to do network I/O:
Blocking. In this mode reads and writes will block until they can be fulfilled, so if you want to do both simultaneously you need separate threads for each.
Non-blocking. In this mode reads and writes will return zero (Java) or in some languages (C) a status indication (return == -1, errno=EAGAIN/EWOULDBLOCK) when they cannot be fulfilled, so you don't need separate threads, but you do need a third API that tells you when the operations can be fulfilled. This is the purpose of the select() API.
Asynchronous I/O, in which you schedule the transfer and are given back some kind of a handle via which you can interrogate the status of the transfer, or, in more advanced APIs, a callback.
You should certainly never use the while (in.available() > 0)/sleep() style you are using here. InputStream.available() has few correct uses and this isn't one of them, and the sleep is literally a waste of time. The data can arrive within the sleep time, and a normal read() would wake up immediately.
You should rather use a boolean variable instead of while(true) to properly close your thread when you will want to. Also yes, you should create multiple thread, one per client connected, as the thread will block itself until a new data is received (with DataInputStream().read() for example). And no, this is not really a design question, each library/Framework or languages have its own way to listen from a socket, for example to listen from a socket in Qt you should use what is called "signals and slots", not an infinite loop.