Find the Race
You are the scheduler. Step each actor in whatever order you like, and try to produce an interleaving that breaks the stated invariant. Nothing is revealed until you have tried — because the skill being practised is enumerating schedules in your head, not recognising a race you were shown.
Two Increments, One Counter
Shared StateThe invariant you are trying to break
Synchronization exists to preserve invariants. If you cannot name one, you are not protecting anything.
Your goal · Find an ordering in which both threads run all three of their steps, both return successfully, and the counter ends at 1 instead of 2. Then find a second, differently-shaped ordering that loses the same increment — the point is that there is not one narrow window but a whole family of them.
20 orderings exist for these actors — an exact count, not a simulation. Your test suite exercises one of them, repeatedly, and calls it passing.
Step the actors
Click an actor to run its next indivisible operation. Any order is legal — that is precisely the problem.
No schedule yet
Step an actor above. The trace builds as you go, and the invariant is checked after every step.
The schedules that break it
Revealed after you have tried. Each one is an ordering a real scheduler is free to produce, and one of them is what your users hit.
Try it yourself first
Step at least one actor above. Being handed the failing interleaving before you have hunted for it teaches nothing.
What fixes it, and what the fix costs
Every one of these works. None of them is free — that is why the choice is a design decision rather than a lookup.
Locked until you have driven the scheduler
Fixes only mean something once you have seen what they are fixing.