Processes, threads, races and locks — DedSec Project
Processes, threads, races and locks Processes and threads Track: Systems Core explanation Processes generally have independent memory spaces, whereas threads within a process share memory…
Processes and threads
Track: Systems
Core explanation
Processes generally have independent memory spaces, whereas threads within a process share memory. Concurrency helps responsiveness but introduces coordination and lifecycle problems.
Hands-on application
Contrast one worker process with two threads modifying shared counters.
How the system actually behaves
A process has its own address space and operating-system resource table; threads within one process share memory but have independent execution stacks. Threads help coordinate blocking I/O, while CPU parallelism depends on language runtime and platform. Python's common CPython GIL does not make compound state updates a safe protocol.
Runnable controlled experiment
import threading
seen=[]
def record(x): seen.append(x)
threads=[threading.Thread(target=record,args=(i,)) for i in range(3)]
for t in threads: t.start()
for t in threads: t.join()
assert sorted(seen)==[0,1,2]
Failure analysis and extension
Replace list appends with a compound read/modify/write state operation, then enforce the invariant with a Lock. Compare thread scheduling with a multiprocessing.Queue where data must cross a process boundary.
Reference: https://docs.python.org/3/library/threading.html
Race conditions and locks
Track: Systems
Core explanation
A race occurs when correctness depends on unpredictable event ordering. Prefer message passing or immutability where possible; locks require a documented acquisition order to avoid deadlocks.
Hands-on application
Explain why read-increment-write is not automatically atomic.
How the system actually behaves
A race condition means correctness depends on unpredictable interleaving. Protect an invariant with one lock spanning the entire read-modify-write critical section, not separate locks around reads and writes. A mutex makes an operation exclusive but excessive locking can cause contention or deadlock.
Runnable controlled experiment
import threading
counter=[0]; lock=threading.Lock()
def increment():
for _ in range(1000):
with lock: counter[0]+=1
threads=[threading.Thread(target=increment) for _ in range(2)]
for t in threads:t.start()
for t in threads:t.join()
assert counter[0]==2000
Failure analysis and extension
Introduce a second lock and describe a lock-order inversion that would deadlock. Repair by imposing a global acquisition order; avoid testing deadlocks without a timeout and disposable process.
Reference: https://docs.python.org/3/library/threading.html#lock-objects