加工草图并发修改异常

Concurrent Modification Exception in Processing Sketch

我正在修改 Toxiclibs library 中的 Attraction2D 示例,使其由 Leap Motion 传感器的手势控制,而不是示例中的鼠标。

我在 Open Frameworks 应用程序中进行所有手势识别,并通过 OSC 发送。

Gesture 0 事件发生时,我调用下面的方法从 physics 对象中删除 gestureAttractor

void resetAttraction() {
  if (gestureAttractor != null){
      physics.removeBehavior(gestureAttractor);
      println("ATTRACTOR NULL");
     } else {
        println("not null");
     }
}

如果发生 Gesture 1 事件,我调用此方法创建一个新的 gestureAttractor,并将其添加回 physics 对象:

void addAttraction(){ 
   if (gestureAttractor == null) { 
       println("ATTRACTOR NULL"); 
       position1.set(340, 191); 
       gestureAttractor = new AttractionBehavior2D(position1, 250, 0.9f); 
       physics.addBehavior(gestureAttractor); 
   } else { 
       println("not null"); 
   } 
}

似乎始终如一地发生的是,只要手势状态发生变化,我就会在 draw 方法的 physics.update(); 处发生 ConcurrentModificationException 崩溃。

我确定这与处理这些对象的生命周期的方式有关,但我还不能确定任何事情 - 有人有任何想法吗?

草图全文如下:

import toxi.geom.*;
import toxi.physics2d.*;
import toxi.physics2d.behaviors.*;

import oscP5.*;
import netP5.*;

OscP5 oscP5;

int NUM_PARTICLES = 750;

VerletPhysics2D physics;
//AttractionBehavior2D mouseAttractor;
AttractionBehavior2D gestureAttractor;


//Vec2D mousePos;
Vec2D position1;


boolean isGestureAttractorAdded;

void setup() {
  size(680, 382,P3D);
  // setup physics with 10% drag
  physics = new VerletPhysics2D();
  physics.setDrag(0.05f);
  physics.setWorldBounds(new Rect(0, 0, width, height));
  // the NEW way to add gravity to the simulation, using behaviors
  physics.addBehavior(new GravityBehavior2D(new Vec2D(0, 0.15f)));

  // start oscP5, listening for incoming messages at port 12000 
  oscP5 = new OscP5(this, 6000);

  position1 = new Vec2D(340, 191);

  addAttraction();

  //gestureAttractor = new AttractionBehavior2D(position1, 250, 0.9f);
  //physics.addBehavior(gestureAttractor);
}

void addParticle() {
  VerletParticle2D p = new VerletParticle2D(Vec2D.randomVector().scale(5).addSelf(width / 2, 0));
  physics.addParticle(p);
  // add a negative attraction force field around the new particle
  physics.addBehavior(new AttractionBehavior2D(p, 20, -1.2f, 0.01f));
}

void draw() {
  background(255,0,0);
  noStroke();
  fill(255);
  if (physics.particles.size() < NUM_PARTICLES) {
    addParticle();
  }
  physics.update();
  for (VerletParticle2D p : physics.particles) {
    ellipse(p.x, p.y, 5, 5);
  }
}

void mousePressed() {
  //position1 = new Vec2D(mouseX, mouseY);
   //create a new positive attraction force field around the mouse position (radius=250px)
  //gestureAttractor = new AttractionBehavior2D(position1, 250, 0.9f);
  //physics.addBehavior(gestureAttractor);

  //println(physics.behaviors);
}

void mouseDragged() {
  // update mouse attraction focal point
  //position1.set(mouseX, mouseY);
}

void mouseReleased() {
  // remove the mouse attraction when button has been released
  //physics.removeBehavior(gestureAttractor);
}


///// OSC RECEIVING

void oscEvent(OscMessage theOscMessage) {
  /* check if theOscMessage has the address pattern we are looking for. */

  if (theOscMessage.checkAddrPattern("/gesture_classification") == true)  {
    /* check if the typetag is the right one. */
    if(theOscMessage.checkTypetag("i")) {
      /* parse theOscMessage and extract the values from the osc message arguments. */
      int gestureClassLabel = theOscMessage.get(0).intValue();  
      println(" Gesture is: ", gestureClassLabel);

      if (gestureClassLabel == 0){   
        resetAttraction();
      } else if (gestureClassLabel == 1) {       
        addAttraction();
      } else if (gestureClassLabel == 2) {
          //physics.removeBehavior(gestureAttractor);
      } 
    }  
  } 

}

//////METHODS FOR SETTING POSITION / REMOVAL OF ATTRACTORS...

void resetAttraction() {
  if (gestureAttractor != null){
      physics.removeBehavior(gestureAttractor);
      println("ATTRACTOR NULL");
     } else {
        println("not null");
     }
 }

void addAttraction(){
     if (gestureAttractor == null) {
         println("ATTRACTOR NULL");
         position1.set(340, 191);
         gestureAttractor = new AttractionBehavior2D(position1, 250, 0.9f);
         physics.addBehavior(gestureAttractor);
     } else {
       println("not null");
     }
}

tl;dr: 在从另一个线程迭代数据结构时,不应使用一个线程修改数据结构。

draw() 函数在一个线程上发生,它正在访问和修改物理库中的数据结构。

oscEvent() 函数正在另一个线程上运行,它也在访问和修改那些相同的数据结构。这就是导致你错误的原因。请注意,将其包装在 try 块中 不会 修复任何问题。它只是在错误发生时打印出更多信息。

要真正解决问题,您需要阅读有关同步线程间数据访问的内容。例如,您可以使用同步块来防止不同的线程访问相同的数据结构。如果您 google 您的错误,您会发现大量结果。