From: Ashley Ward
To: Meurig Beynon
Subject: Re: Lift stuff
Date: Wed, 1 Oct 2003 21:47:17 +0100
On Wednesday, October 1, 2003, at 08:44 am, Meurig Beynon wrote:
> /dcs/acad/wmb/public/projects/simulations/LIFT/LUCERNE
OK... I've had a look and I've got a reasonable understanding of why
tkeden is behaving as it is with this model.
***
The quick answer: I think you'll be a lot more satisfied with it if you
add an eager() to the delay procedure, as below:
proc delay {
para delaytime;
auto ft0, ft;
ft0 = ftime()[1];
ft = ft0;
while ((ft - ft0) < delaytime) {ft = ftime()[1]; eager();}
}
***
The long answer:
Eden is a sequential, singly threaded machine. There's only one thing
executing at a time. Here's an example interaction with ttyeden:
8|> for (i = 1; i < 1000000; i++) { };
writeln("hi");
9|> writeln("hi");
hi
Whilst the for loop was executing, I typed writeln("hi"); on the second
line, and ttyeden ignored it (the echoing of my typing is done by the
OS -- well, actually the terminal libraries, I think). When ttyeden
was finally ready for me, it read the buffered input, shown on the
third line, and runs it.
So whilst a procedural block is executing, Eden doesn't do anything
else. This includes loops like above, also blocks of code in procs and
funcs, also calls that procs or funcs make to other procs or funcs,
also procs that are triggered by change. When all these things have
terminated, the machine is in a "consistent" state and Eden stops
executing and deals with input.
Now tkeden. The GUI interface is actually driven by Tk. Tk only gets
a chance to do interface tasks when Eden calls the Tk "update" routine.
When this is called, Tk updates the screen display with any changes,
reads input from the input window, deals with mouse clicks etc. If
Eden doesn't call the Tk update routine, none of these things happen,
and the interface "freezes". Eden doesn't call this routine whilst it
is executing a procedural block of code etc: see above.
The exception to these rules described so far is eager(). Calls to
eager evaluate the formula queue and then call the Tk update routine.
In ttyeden, this has no effect, because ttyeden doesn't use Tk for
input / output handling (and actually the call to Tk update is
conditionally compiled out in ttyeden).
12|> for (i = 1; i < 1000000; i++) { eager(); };
writeln("hi");
13|> writeln("hi");
hi
In tkeden, saying this in the input window freezes the interface until
control-c is pressed (note even pressing the Interrupt button doesn't
work because this relies on the Tk update routine to function):
while (1) { };
However, saying this allows the interface to continue "normally":
while (1) { eager(); };
... although from the point of entering this command onwards, the Eden
machine is actually continuously executing an eager loop (repeated
calling the Tk update routine). Notice that the messages after
pressing the Interrupt button after running this line say that the
RunSets have been cleared... pressing the Interrupt button normally
just acknowledges that the button has been pressed.
***
The above may help you right now. A "proper" solution is much more in
depth and will require discussion about what you are actually
expecting. It seems to me that you want the machine to pause when
variables mentioned in keylist are changed. But I don't think that's
realistic: this solution causes all agents to be paused, including the
user input, because Eden is a sequential, singly threaded machine.
1 procmacro playlift {
2 _liftfloor = 3;
3 if (commentary) {
4 writeln("\TRAVAILS IN A LIFT");
5 writeln("\nX, Y and I wait for lift\n");
6 }
7 locX = locY = locI = 1;
8 destX = destI = 4;
What's actually going on here:
line 2: change to _liftfloor triggers keylist, causes delay.
between 2 + 3: my procmacro code has inserted an eager, so screen
updates and user input is allowed
line 3, 4, 5, 6: possibly an eager between each of these lines
line 7: locX, then locY, then locI (or possibly the other way around
depending on precedence) trigger keylist and cause 3 calls to delay.
between 7 and 8: a call to eager, so it looks like your line 7 was
"atomic" (although see my comments for line 7: it isn't, at that level
of consideration).
line 8: doesn't trigger keylist, so no delay
after line 8: call to eager...
We could rewrite as something like
proc playlift {
_liftfloor = 3;
if (commentary) {
writeln("\TRAVAILS IN A LIFT");
writeln("\nX, Y and I wait for lift\n");
}
delay(1);
locX = locY = locI = 1;
delay(1);
destX = destI = 4;
... but we still have the problem that user input isn't allowed during
delay() (unless you insert eager() as I suggest).
Perhaps ultimately we need to store a list of transitions that you want
to make here possibly with information about pauses, and have a
procedure that goes something like (pseudo-code):
proc nextinstruction {
if enough time has elapsed since the last instruction:
look up next instruction in list
execute() it
todo("nextinstruction();");
}
Hum.
Or really it needs rethinking in terms of my PhD notions of multiple
agents, each with their own "atomicity" of view.
...
(the suggested change to the delay() procedure has been made in the
liftBeynon2003 model).
Ashley
October 2003