Fix the lock checker for a shared hit cache
Your task
An AI agent wrote a hit cache for your game server's worker threads: a shared hash map, a find, and an insert on a miss. It called this "safely memoized", but nothing synchronized the map, and its single-threaded test passed. Your team now replays recorded thread interleavings through a checker. Every access to the shared map must happen while the acting thread holds the one mutex.
An assistant wrote check_lock_discipline(operations), the checker. It is in the editor. It has a bug. Find it and fix it.
Input and output:
operations: one operation per line, in the order they happened, writtenthread|actionorthread|action|key. The actions arelock,unlock,findandinsert. Thread names are never empty.- Return the violations, in the order they occur.
Rules the tests check:
- Split a line on
|. Skip it if it has fewer than 2 parts. The key is the third part, or empty if there is none. Parts after the third are ignored. - There is one mutex, and it starts free. Skip any action other than the four above.
- In every report,
<thread>is the thread on that line. lock: if the mutex is free, the thread now holds it. If the same thread already holds it, reportdouble_lock:<thread>. If another thread holds it, reportlock_held_by_other:<thread>, naming the thread that tried to lock. In both of those cases nothing changes.unlock: if the thread holds the mutex, it becomes free. Otherwise reportunlock_without_lock:<thread>.findorinsertby a thread that does not hold the mutex: reportunsynchronized_find:<thread>:<key>orunsynchronized_insert:<thread>:<key>.- After the last line, if a thread still holds the mutex, report
lock_not_released:<thread>for that thread.
Examples
check_lock_discipline(operations: list[str]) -> list[str]Example 1
Input
check_lock_discipline(["t1|find|7", "t2|find|7", "t1|insert|7", "t2|insert|7"])Output
["unsynchronized_find:t1:7", "unsynchronized_find:t2:7", "unsynchronized_insert:t1:7", "unsynchronized_insert:t2:7"]Example 2
Input
check_lock_discipline(["t1|lock", "t1|find|7", "t1|insert|7", "t1|unlock", "t2|lock", "t2|find|7", "t2|unlock"])Output
[]