Thread safety refers to ensuring that shared data structures and resources can be accessed and modified correctly by multiple threads without causing inconsistencies or errors.
import threading
counter = 0
def increment():
global counter
for _ in range(100000):
counter += 1
# Create two threads to increment the counter
thread1 = threading.Thread(target=increment)
thread2 = threading.Thread(target=increment)
thread1.start()
thread2.start()
thread1.join()
thread2.join()
print(f"Final counter value: {counter}") # Output varies due to race condition
Concurrent data structures are designed to be safely accessed and modified by multiple threads simultaneously, typically using synchronization mechanisms to prevent race conditions.
queue
module (Queue
, PriorityQueue
, LifoQueue
) for synchronized access.Example using Queue
:
from queue import Queue
import threading
q = Queue()
def worker():
while True:
item = q.get()
# Process item
q.task_done()
# Create threads to process items from the queue
for _ in range(5):
threading.Thread(target=worker, daemon=True).start()
# Add items to the queue
for item in range(10):
q.put(item)
q.join() # Wait for all items to be processed
Synchronization primitives are mechanisms used to coordinate access to shared resources and prevent simultaneous access by multiple threads.
Example using threading.Lock
:
import threading
counter = 0
lock = threading.Lock()
def increment():
global counter
for _ in range(100000):
with lock:
counter += 1
# Create two threads to increment the counter
thread1 = threading.Thread(target=increment)
thread2 = threading.Thread(target=increment)
thread1.start()
thread2.start()
thread1.join()
thread2.join()
print(f"Final counter value: {counter}") # Output: 200000 (consistent due to lock)
Example using threading.Semaphore
:
import threading
semaphore = threading.Semaphore(2) # Allow two threads to access at a time
def access_resource():
with semaphore:
# Access shared resource
pass
# Create multiple threads to access the resource
threads = []
for _ in range(5):
t = threading.Thread(target=access_resource)
threads.append(t)
t.start()
for t in threads:
t.join()