On slide 12, the second version of the Eraser algorithm is used which will only flag errors if a variable was indeed shared and its candidate set is empty. That is why we assume there that thread T1 sets v to 1024, then thread T2 writes to v while holding mu1, which puts the variable in the shared-modified state. Once thread T1 writes to v while holding mu2, an error is flagged.
Note that this example is a bit contrived. You would be more likely to encounter this example in a form similar to this:
function f() {
lock(mu1);
v := v + 1;
unlock(mu1);
}
function g() {
lock(mu2);
v := v + 1;
unlock(mu2);)
}
function body() {
f();
g();
}
thread t1 = thread_create(body);
thread t2 = thread_create(body);
Here, the sequence is first executed in its entirety by one thread, and later another thread executes the
same sequence.
Eraser will detect a race condition in this less contrived scenario as well (think about
how it would do it and what the states of v will be!)
Finally, the example shown on 16/17, which is one of the cases in which even the refined version of Eraser might miss a race condition, can be fixed by adding additional states, as suggested by Seragiotto. John shows the expanded state diagram in an expanded version of his slides (on Slide 22).