Synchronize access to array

Hi, I’m having problems with an array being updated inside SerialEvent handler.
This is the case:

  1. I’m using grafica library
  2. I get some data from an Arduino through the serial port. I handle this through a SerialEvent handler.
  3. I update a GPointsArray inside the SerialEvent handler.
  4. In the draw() loop I draw the incoming data.

The problem is I keep getting “IndexOutOfBoundsException” when calling the draw method of the plot, and the error doesn’t make sense. For example: “IndexOutOfBoundsException: Index: 29, Size: 62”. It’s clear that the index is in bound.
The problem seems to be that the SerialEvent handler and the draw() function are both trying to access the array at the same time. Any suggestion?

This is a simplified code to reproduce the error:

import processing.serial.*;
import grafica.*;

Serial port;
GPlot plotPos;
GPointsArray ws;

int wsN = 100;

void setup() {
  size( 800, 600 );

  ws = new GPointsArray(wsN);  //Create th points array


  plotPos = new GPlot(this);  //Create a new plot

  plotPos.setPoints(ws);
  plotPos.setPos(20, 20);
  plotPos.setDim(width *0.82, height*0.6);

  if ( openComm() == 1 ) {
    exit();
  }
}

void draw() {
  plotPos.defaultDraw();  //Draw everything
}

void serialEvent(Serial port) { 
  String inString = port.readString();


  if ( ws.getNPoints() >= wsN )
    ws.remove(0);

  ws.add(mouseY, mouseX);  //Add some random data to the array.
  plotPos.setPoints(ws);

  inString = "";
}


int openComm() {
  String[] serialPorts = Serial.list(); //Get the list of tty interfaces
  for ( int i=0; i<serialPorts.length; i++) { //Search for ttyACM*
    if ( serialPorts[i].contains("ttyACM") || serialPorts[i].contains("ttyUSB0") || serialPorts[i].contains("COM") ) {  //If found, try to open port.
      println(serialPorts[i]);
      try {
        port = new Serial(this, serialPorts[i], 115200);
        port.bufferUntil(10);
      }
      catch(Exception e) {
        return 1;
      }
    }
  }
  if (port != null)
    return 0;
  else
    return 1;
}

Hi @pcremades :wave:;

I have been learning some of CUDA recently and graphics have that problem (you can’t access to the same memory from different places at the same time); what you should do is use atomic functions ( functions that guarantees it waits till one function have finished to access that place of memory before other function access the same place).

Don’t know much about your code, just have read your comments and figured that can be the solution (maybe I’m mistaken, but if not maybe that information can help you)… here maybe you can use some functions as delay(); or use flags to control your access to the memory.

Hope you find the solution :hugs: good luck :four_leaf_clover:

Hi @Waboqueox,
Thank you for your reply.
I’m not sure if SerialEvent runs in a different thread, but it seems to be like that. I thought about making draw() wait until SerialEvent finishes writing the array, but can’t find a way to do that.
I don’t even know if that would be the right way to solve the problem.

Most Processing libs that have callback names w/ the word “event” on them are indeed threaded. :thread:

There are many ways to workaround threading access/mutation; but I prefer to start w/ the simplest 1s before attempting more advanced techniques. :man_technologist:

If your sketch just needs to refresh the draw() when a new data arrives, you can simply use this noLoop()/redraw() combo: :bulb:

1 Like