CIT 594 Threading Suggestions for Interpreter
Spring 2006, David Matuszek

The GUI has Start, Pause/Resume, and Stop buttons. This is fairly typical for a program that does animation under the users control. For these buttons to work properly, they must be in a Thread that is separate from the Thread that performs the animation.

Note that while it is possible to pause, resume, and stop a Thread directly from another Thread, these methods are deprecated, because they may leave objects in an invalid state. Instead, the correct approach is to set flags that the other Thread can check, and pause or stop itself.

Two approaches

There are two ways to create and execute a Thread. Here's the slightly simpler way:

  1. Write a class that extends Thread.
  2. Supply a method public void run() in that class.
  3. Create an object of that class.
  4. Send the object the message start().

Since a class may only extend one other class, and the above requires that you extend Thread, there is a second and more flexible way to create and execute a Thread:

  1. Write a class that implements Runnable.
  2. Supply a method public void run() in that class.
  3. Create an object of that class.
  4. Create a Thread with that object as a parameter: new Thread(myObject).
  5. Send the Thread (not the object) the message start().

Since my Interpreter does not extend any other class (loosely speaking; by default, of course, it extends Object), I could have used either approach. For no particular reason, I chose the second.

The Start button

I only created one Interpreter object, which I reuse. It's also possible to create a new Interpreter each time you execute a Logo program, if for some reason that's more convenient.

When the Start button is clicked, here's what I do:

  1. Read in (from the text area) the Logo program and parse it.
  2. Get the parse tree from the Parser and send it to the Interpreter.
  3. Create a new Thread (giving it the interpreter as a parameter), and tell it to start.
if (parser.program()) {
    Tree tree = parser.getParseTree();
    interpreter.setParseTree(tree);
    Thread thread = new Thread(interpreter);
    thread.start();
}

You need to catch two kinds of exceptions: Parse exceptions, and Interpreter exceptions. Your error messages should be as helpful as you can reasonably make them.

The Pause/Resume button

You could have two different buttons, Pause and Resume. In a GUI, you should always disable (gray out) any controls that are not currently applicable, so at least one of these buttons should always be disabled. I found it easier just to have one button, and relabel it.

Either way, clicking this button should just send a message to the interpreter.

interpreter.setPaused(pause);

The main loop of the interpreter needs to check for this. Ideally this would be done with wait and notify, but I was lazy and did it this way:

while (paused) {
    try { Thread.sleep(50); }
    catch (Exception e) { }
}

The Stop button

In LogoGui: interpreter.setTerminated(true);

In the Interpreter's main loop: if (terminated) return;

When the Interpreter finishes execution, the Thread dies, and cannot be resurrected. Hence, the only way to run the program again (or another program) is to have the Start button create a new Thread.

The speed control

As the program executes, you want it to pause between operations that cause a visible change on the screen (and only those operations). Do this with a Thread.sleep(delay); message. This could be done in the interpreter, on a case-by-case basis, but I found it slightly easier to do in the Turtle, each time it tells the TurtleCanvas to repaint().