Multithreaded programming is notoriously difficult to get right. A key problem is non-determinism, which complicates debugging, testing, and reproducing errors in multithreaded applications. One way to simplify multithreaded programming is to enforce deterministic execution. However, past deterministic systems are incomplete or impractical. Language-based approaches require programmers to write...