Tag(sp22)
We're updating Forge soon–-likely this evening or tomorrow. There are some improvements to the sequence library. But there is also a fix to logging, which was previously not happening.
Since logging is now enabled, I want to be open about what we're logging, and how you can opt out if you wish.
By default, the new Forge version will record, for every run:
forge/bsl
);These all get saved into a temporary directory you can find by running:
These files are periodically uploaded to the cloud for storage (so they won't eat up too much disk space).
Forge (especially Froglet) is under active development. Some error messages are currently terrible, and there are the occasional crash bugs etc. Logging helps us make improvements we might not think to make on our own, unless you manually file a bug report. It's also useful for evaluating how effective teaching Froglet was this year.
However, we understand that you might prefer to not participate in logging.
If you wish to turn off logging, just leave off the project ID and anonymous ID on the #lang
line of your file. E.g., instead of:
for curiosity modeling, you'd just use:
Doing this will disable the logging infrastructure.
While we hope you'll keep logging on, whether or not you have logging enabled will not affect your grade in the course.
If you decide to not use logging, we understand–-and hope you'll continue to file manual bug reports (with details and context) here.
If you have two independent threads running concurrently, many subtle bugs can manifest. For instance, if both threads can write to the same region of memory, they might overlap their writes. A great example of this is simply incrementing a counter. If both threads have:
in their code, then the following sequence of operations would be problematic:
counter
counter
1
to that valuecounter
1
to that valuecounter
1
higher than its original value.We often call the property that such traces can't exist mutual exclusion, and the piece of code that shouldn't ever be run by 2 threads at once the critical section.
Today we'll model a very simple approach to mutual-exclusion. The approach turns out not to work, but it's one of the first "bad" solutions you'd see in a course like 1760.
Consider the pseudocode below, and imagine it running on two separate threads of execution. I've marked program locations in square brackets–-note how they correspond to the spaces in between lines of code executing.
Both processes will always continuously try to access the critical section. When they become interested, they set a public flag
bit to true. Then, they don't enter until their counterpart's flag is false. When they're done executing the critical section, they lower their flag and restart.
Notice we aren't modeling the critical section itself. The exact nature of that code doesn't matter for our purposes; we just want to see whether both process can be at the in-cs
location at once. If so, mutual exclusion fails!
We'll start with sigs:
An initial state is one where all processes are disinterested, and no process has raised its flag:
We then have three different transition predicates, each corresponding to one of the lines of code above, and a transition predicate delta
that represents any currently-possible transition:
We won't create a Trace
sig or traces
predicate at all. We're going to do everything with induction today.
Before we run Forge, ask yourself whether the algorithm above guarantees mutual exclusion. (It certainly has another kind of error, but we'll get to that later. Focus on this one property.)
It seems reasonable that the property holds. But if we try to use the inductive approach to prove that:
The inductive case fails. Let's see what the counterexample is:
Yields:
or, in the table view:
Notice that neither process has raised its flag in either state. This seems suspicious…
This counterexample shows that the property we wrote isn't inductive. But it might still an invariant of the system–-it's just that Forge has found an unreachable prestate. To prevent that, we'll add more conditions to the good
predicate (we call this enriching the invariant or proving something stronger). Let's say that, in order for a process to be in the critical section, its flag needs to be true:
But the inductive case still fails! Let's enrich again. The flag also has to be raised if a process is waiting for its counterpart's flag to become false:
Now the inductive check passes. We've just shown that this algorithm satisfies mutual exclusion.
We should probably make sure the two proof steps aren't passing vacuously:
The link is here.