Fix the Deadlock Bug in Concurrent Transaction Simulation
Identify and fix a concurrency deadlock bug in a Python simulation of database transactions using locks. The broken code attempts to simulate two concurrent transactions that acquire multiple locks and cause a deadlock, resulting in a hang. Your task is to fix the code to avoid deadlocks while preserving the transactional behavior.
Challenge prompt
You are given a Python script simulating two concurrent transactions attempting to lock shared resources. The code causes a deadlock because each transaction waits indefinitely for locks held by the other transaction. Your challenge is to fix the deadlock by reordering locks or implementing a proper locking mechanism so that both transactions can complete successfully without deadlocks. You are not allowed to use external concurrency control libraries; instead, fix the logic within the existing threading and locking code.
Guidance
- • Analyze the order in which each transaction acquires locks and identify conflicting sequences that lead to deadlock.
- • Consider reordering lock acquisitions or implementing a consistent global lock acquisition order.
- • Test the fixed code by running the simulation multiple times to ensure no deadlocks occur.
Hints
- • Deadlocks often happen when multiple threads acquire multiple locks in different orders.
- • A common fix is imposing ordering on lock acquisition, so all threads attempt to acquire locks in the same global order.
- • Use try-finally blocks or context managers to ensure locks are always released properly.
Starter code
import threading
lock_a = threading.Lock()
lock_b = threading.Lock()
def transaction1():
print('Transaction 1: Acquiring lock A')
lock_a.acquire()
print('Transaction 1: Acquired lock A')
# Simulate work
threading.Event().wait(1)
print('Transaction 1: Acquiring lock B')
lock_b.acquire()
print('Transaction 1: Acquired lock B')
print('Transaction 1: Releasing locks')
lock_b.release()
lock_a.release()
def transaction2():
print('Transaction 2: Acquiring lock B')
lock_b.acquire()
print('Transaction 2: Acquired lock B')
# Simulate work
threading.Event().wait(1)
print('Transaction 2: Acquiring lock A')
lock_a.acquire()
print('Transaction 2: Acquired lock A')
print('Transaction 2: Releasing locks')
lock_a.release()
lock_b.release()
thread1 = threading.Thread(target=transaction1)
thread2 = threading.Thread(target=transaction2)
thread1.start()
thread2.start()
thread1.join()
thread2.join()
print('Both transactions completed')Expected output
Transaction 1: Acquiring lock A Transaction 1: Acquired lock A Transaction 2: Acquiring lock B Transaction 2: Acquired lock B // Then either transaction proceeds without deadlock until both complete Both transactions completed
Core concepts
Challenge a Friend
Send this duel to someone else and see if they can solve it.