While loop bug? Stuck on empty


#1

Hi

I have a weird bug in a sketch that I’m using to control a plotter.
I have a while loop that is controlled by a boolean that is switched to false while the plotter is in the middle of doing something. Once the plotter is finished it sends a serial command to my sketch and flips nextMove=true;
This aspect of it is working correctly and I am checking the nextMove variable and it is set to true.

The weird part the sketch gets stuck in the loop even though the variable is set to true. If I put a prinlnt statement (as below) into the loop it doesn’t get stuck.
I don’t want to print endlessly to the console as I cant read my other debug messages.

Any ideas? I tried to give the loop another meaningless task incrementing a variable but it still gets stuck. The print statement is all that will move it along.

Thanks

    nextMove=false;  
    boolean printOnce = true; 

while (nextMove == false) {                // wait for plotter not to be busy
      if(printOnce)println("Waiting for plotter to move home");      //print busy message
      //println("Stuck in while loop");
      printOnce = false;
    }

#2

There is nothing inside the while loop to change nextMove to true so if it is false when we reach the loop then program execution it stays indie the loop. The only way out is if it is changed in another thread.


#3

Hi,

Yeas, nextMove is changed in another thread that is listening for serial feedback from the plotter.
As I mentioned the loop functions as intended if the print statement is uncommented but if the statement is commented out it gets stuck. Which seems a bit odd to me.

Does that make sense?

On another note - I realised I was setting needlessly printOnce each time so I moved it into the if statement as below.

    nextMove=false;                            // tell loop plotter is busy
    boolean printOnce = true;                  // control for busy message
    while (nextMove == false) {                // wait for plotter not to be busy
      if(printOnce){
        println("Waiting for plotter to move home");      //print busy message
        printOnce = false;
      }
      println("Stuck in while loop");
      
    }

#4

Just to clarify - the purpose of the while loop is to wait for the nextMove command to be set true again based on external input from the plotter.

Thanks


#5

It could be that with the print statements commented out the while-loop is hogging the CPU. I suggest that you put the thread to sleep for about 20 milliseconds inside the loop so that the other threads are not starved of CPU time.


#6
  • Is your while () loop under the “Animation” Thread?
  • If it is so, you’re better off calling noLoop() in place of that loop.
  • And have your other Thread calling loop() or redraw() instead of nextMove = true;.

#7

Hi Thanks for the help.

@GoToLoop yeah at the moment the the function that is talking to the plotter is called from the main draw thread. I should put this in another thread I guess? I don’t want to call noLoop() as I want an animation to still run on screen while the plotter is drawing the image. (Although at the moment of course this is not working as the draw() function needs to wait until the plotter has done its thing. So I will need to thread this anyway.

@quark Okay, good idea. Is Thread.sleep(20) the right way to go about this? this seems to throw an interupt exception.

Thanks
T


#8

Just use delay(): Processing.org/reference/delay_.html
But make sure it’s outside the “Animation” Thread. :warning:


#9

HI,

Great. I rejigged things and put the plotting function in another thread - so that side of it is sorted.
I also swapped the println for a delay - it seems to work sometimes and then stop other times. I presume that what is happening is the serial command is coming back to it during the delay or something like that.
I guess its the classic fix one bug and theres another few waiting in store.
Thanks for the help.


#10

If doing this you should make sure the boolean field is also marked volatile. The other thread is effectively allowed to ignore the fact that it’s changed otherwise, particularly a problem in a hard loop! The JIT compiler can end up compiling your code such that the check happens once before your loop. The print is probably changing this behaviour.


#11

HI. Ah cool. I didn’t know about that. So just declare it as volatile boolean.

Just so I understand it better - what’s the difference between a volatile boolean and a regular one? Is it that it can be read and written from different threads so that the thread in question has to check its value each time its references instead of assuming it is the same as it last set it?

thanks for the help, I don’t have much coding experience so I get a bit lost when I stray off the paths that I am familiar with.


#12

That’s close enough! You could have a read of https://en.m.wikipedia.org/wiki/Java_memory_model for a bit more on caching / as-if-serial / reordering.


#13

Great, thanks for the heads up. I’ll have a look and see whether it works when I get back into the studio.
Thanks


#14

Only for extreme tight loops like while (!nextMove) { }, w/o anything to it, would cause JIT to never check whether the non-volatile field nextMove had changed its value.

For any healthy regular loops, JIT will eventually check non-volatile fields, and break outta the loop!

If it wasn’t so, the whole Java ecosystem would crumble in an instant due to your non-volatile fields doomsday multi-threading scenario!

We can confidently use a loop to await for any non-volatile field to be changed from another Thread!

Here’s a practical example, which awaits for Capture::width to have non-zero value in a while () loop under the sketch’s own “Animation” Thread:

/**
 * Efficient WebCam Capture (2.0.1)
 * GoToLoop (2016-May-05)
 *
 * Forum.Processing.org/two/discussion/16435/
 * how-to-make-the-webcam-capture-window-go-away-or-put-images-over-it
 *
 * GitHub.com/processing/processing-video/pull/30
 */

import processing.video.Capture;
Capture cam;

static final String RENDERER = JAVA2D;
//static final String RENDERER = FX2D;

static final int CAM = 1, FPS_ADJUST = 5, DELAY = 5;

void setup() {
  size(640, 480, RENDERER);
  initFeed();

  float canvasFPS = cam.frameRate + FPS_ADJUST;
  frameRate(canvasFPS);

  println("Cam's FPS:", cam.frameRate, "\t\tCanvas's FPS:", canvasFPS);
  print("Cam's size:", cam.width, 'x', cam.height, '\t');
  println("Canvas's size:", width, 'x', height);
}

void draw() {
  background(cam);
  getSurface().setTitle( str(round(frameRate)) );
}

void captureEvent(final Capture c) {
  c.read();
}

void initFeed() {
  String[] cams = Capture.list();
  printArray(cams);
  println("\nChosen Cam #" + CAM + ':', cams[CAM]);

  ( cam = new Capture(this, cams[CAM]) ).start();

  println("cam.width: " + cam.width); // cam.width: 0
  while (cam.width == 0)  delay(DELAY);
  println("cam.width: " + cam.width); // cam.width: 640

  if (cam.width > 0)  getSurface().setSize(cam.width, cam.height);
}

Pay attention to this particular code block:

println("cam.width: " + cam.width); // cam.width: 0
while (cam.width == 0)  delay(DELAY);
println("cam.width: " + cam.width); // cam.width: 640

Before while (cam.width == 0) delay(DELAY); starts, println() is used to log the current value of Capture::width non-volatile field, which is still 0.

Of course that loop, which is run by the “Animation” Thread btW, expects Capture’s own Thread to change its non-volatile field width.

Even though the “Animation” Thread coulda cached the non-volatile field Capture::width, it will eventually check whether the real Capture::width has changed its value.

According to your scenario, the “Animation” Thread would never be aware of the changes made to Capture::width by Capture’s own Thread!


#15

I have no desire to go over the same argument with you again @GoToLoop No vaguely competent Java programmer is going to agree with you. The JMM exists for a reason - working outside of it you cannot be confident of anything. You may have code that works in one scenario, on one JVM, on one OS or CPU (hardware behaviour very relevant here too) - that does not mean you can be confident in it. Your camera example is a particularly useless example for this - it’s almost certainly not going to be JIT compiled, and you also have no idea what’s going on in the underlying libraries (maybe ask the maintainer! :wink:) that could cause visibility to happen. It has no bearing on your point, or the OP’s problem! (it’s also going to break with P2D / P3D if you have a slow system)


#16

I agree! But it’d be cool if you’d come up w/ some code example which demos your point. :sunglasses:


#17

This thread! Probably. Any code that goes counter to the JMM is potentially buggy. You’re asking for a code example that consistently demonstrates something that is by definition not guaranteed to be consistent! You’ll find enough examples of problematic code if you google for it. Some things may fail almost immediately, some after enough time for the JIT to really kick in (minutes or hours), some almost randomly.

It’s quite simple, really - follow the spec! :smile:


#18

Hi.

Thanks, this is really useful information. I read the spec you linked above: https://en.m.wikipedia.org/wiki/Java_memory_model
From what I can make of it the possible reordering of processes at compilation is computed based on happens-before order. I think I get this, but presumably there is no way to really work out what the order is between threads.
In which case - is the advice always to mark a variable as volatile if it is used by multiple threads? Or at least if their completion requires that a thread may have a specific value?
Thanks


#19

Yes, or something that has the same guarantees, such as accessing inside a synchronized block (on both threads, on the same lock!) or getting more complicated, the various other locks and atomic things in java.util.concurrent (eg. there is an AtomicBoolean that can atomically compare and set)

If you have a situation where two threads are reading / writing to the same variable and each thread doesn’t care about the other, you probably shouldn’t be using a shared variable in the first place! :smile:


#20

Yes, or something that has the same guarantees, such as accessing inside a synchronized block (on both threads, on the same lock!) or getting more complicated, the various other locks and atomic things in java.util.concurrent (eg. there is an AtomicBoolean that can atomically compare and set)

Grand, I think I can manage it with volatile for now anyway.

f you have a situation where two threads are reading / writing to the same variable and each thread doesn’t care about the other, you probably shouldn’t be using a shared variable in the first place!

Yeah, I suppose I can’t think of anything where this is the case - I guess I was thinking about something where the variable was being read for some less important reason that didn’t require it to be fully synced with the timing of the other thread. But obviously it still does cares.
Anyway, thanks for all the help. I hadn’t come across volatile variables before so it’s great to understand them (somewhat).