Recitation 20: Concurrency, locks, and monitors
(Outline)
- Concurrent programs
-
Needed for multi-processors, multi-cores, communication with human users, communication with slow devices, distributed systems, etc.
Underlying issue: Performance
- Initial Warning: Emphasize correctness over performance. It's easier to make a correct program efficient than an efficient program correct.
- Kinds of concurrency:
- Shared memory: Concurrent components communicate by reading and writing memory locations
- Message passing: ...by sending and receiving messages
- Some people claim that message passing is easier to reason about (and thus write correct programs), whereas shared memory is more efficient
- Threads
- A thread is [imperatively] a sequential flow of control, or [functionally] a single expression to be evaluated
- Multithreading: more than one flow of control, or more than one expression evaluated simultaneously
- Threads share a single address space
- Threads are lightweight: Creation, maintenance, destruction is (or should be) cheap
- Basic design for modern threads comes from language Modula-2+, circa mid-1980s.
- Creation: fork
- Destruction: reach end of control flow, or evaluation. Sometimes libraries provide ways to aggressively terminate threads, but this is dangerous.
- Example: Race condition on bank account balance
- Real world race conditions: THERAC-25, Mars Rover, NE blackout '03
- Synchronization
- Three techniques: Mutexes, condition variables, monitors
- Mutexes
- Acquire, release, lock
- Rules
- All shared mutable data MUST be associated with some mutex (1 mutex -> 1 or more shared data)
- That association MUST be documented
- Shared mutable data MUST NOT be accessed unless its associated mutex is locked
- Any invariant (e.g., RI) of the shared data MUST be true whenever the mutex is unlocked
- Deadlock example. One solution: impose order on mutex acquisition
- Condition variables
- Wait, signal, broadcast
- Producer/consumer buffer example
- Not covered in recitation:
- Hoare vs Mesa semantics
- Naming convention: why you wait vs why you wake up
- How many? As many as reasons you might wait. Or, Java and C#: only 1
- Documenting: Mutex protected by, assertion for when it should be awakened
- Since wait releases mutex, must ensure invariants hold before waiting
- Monitors
- Shared data + 1 mutex + 1 or more condition variables
- Often a language construct, sometimes a pattern
- Java and C#: monitors with 1 implicit mutex and condition variable
- Final Warning: Emphasize correctness over performance. It's easier to make a correct program efficient than an efficient program correct.