RELATED TAGS
Race condition is a significant problem in concurrent programming. The condition occurs when one thread tries to modify a shared resource at the same time that another thread is modifying that resource – t​his leads to garbled output, which is why threads need to be synchronized.
The threading
module of Python includes locks as a synchronization tool. A lock has two states:
A lock can be locked using the acquire()
method. Once a thread has acquired the lock, all subsequent attempts to acquire the lock are blocked until it is released. The lock can be released using the release()
method.
Calling the
release()
method on a lock, in an unlocked state, results in an error.
The following code shows how locks can be used in Python with a simple example:
Suppose that there are 100 dollars in a bank account. Every month, 10 dollars are deposited as profit, and 10 dollars are deducted to pay a bill. thread1
deposits the profit and thread2
pays for the bill. In some months, the profit is deposited after the bill is paid. However, this should not affect the final amount in the account.
The final answer might be incorrect due to the race condition. There may be cases where a thread is unable to write the updated value to the shared variable deposit before the context switch, and the other thread reads a non-updated value; thus, leading to an unpredictable result.
You may have to run the code several times to re-create the error.
# Importing the threading module import threading deposit = 100 # Function to add profit to the deposit def add_profit(): global deposit for i in range(100000): deposit = deposit + 10 # Function to deduct money from the deposit def pay_bill(): global deposit for i in range(100000): deposit = deposit - 10 # Creating threads thread1 = threading.Thread(target = add_profit, args = ()) thread2 = threading.Thread(target = pay_bill, args = ()) # Starting the threads thread1.start() thread2.start() # Waiting for both the threads to finish executing thread1.join() thread2.join() # Displaying the final value of the deposit print(deposit)
The code between the acquire()
and release()
methods are executed atomically so that there is no chance that a thread will read a non-updated version after another thread has already made a change.
# Importing the threading module import threading # Declraing a lock lock = threading.Lock() deposit = 100 # Function to add profit to the deposit def add_profit(): global deposit for i in range(100000): lock.acquire() deposit = deposit + 10 lock.release() # Function to deduct money from the deposit def pay_bill(): global deposit for i in range(100000): lock.acquire() deposit = deposit - 10 lock.release() # Creating threads thread1 = threading.Thread(target = add_profit, args = ()) thread2 = threading.Thread(target = pay_bill, args = ()) # Starting the threads thread1.start() thread2.start() # Waiting for both the threads to finish executing thread1.join() thread2.join() # Displaying the final value of the deposit print(deposit)
RELATED TAGS
View all Courses