Multiple threads accessing shared resources must be coordinated to avoid deadlocks.
When threads need exclusive access to a resource (like a database row or a file), they acquire a Lock (or Mutex). But what happens if Thread A holds Lock 1 and wants Lock 2, while Thread B holds Lock 2 and wants Lock 1?
They wait forever. This is a Deadlock. We can visualize this using a Wait-For Graph: nodes are threads and locks. An edge from Thread → Lock means "waiting for". An edge from Lock → Thread means "held by". If this graph contains a Cycle, you have a deadlock!
# To avoid deadlocks, threads should always acquire locks
# in the SAME globally agreed-upon order.
def safe_transfer(account_a, account_b, amount):
# Lock the account with the smaller ID first!
first_lock = min(account_a.id, account_b.id)
second_lock = max(account_a.id, account_b.id)
with first_lock:
with second_lock:
# Safely transfer money
account_a.balance -= amount
account_b.balance += amount
# By enforcing order, a cycle can never form in the Wait-For graph.