Unexpected behavior with global variables in threads

Loading

When using global variables in Python multithreading, you may experience unexpected behavior due to race conditions, shared state issues, and improper synchronization.


1. Common Issues and Fixes

A. Race Condition: Multiple Threads Modifying a Global Variable

A race condition occurs when multiple threads access and modify a shared global variable simultaneously, leading to unpredictable results.

Example (Unexpected Behavior)

import threading

counter = 0 # Global variable

def increment():
global counter
for _ in range(1000000):
counter += 1 # Not atomic, can cause incorrect values

threads = []
for _ in range(5):
t = threading.Thread(target=increment)
t.start()
threads.append(t)

for t in threads:
t.join()

print("Final counter value:", counter) # Expected: 5,000,000 | Actual: Unpredictable!

Issue: counter += 1 is not atomic; it involves read → modify → write, which can be interrupted by other threads, causing lost updates.

Fix: Use threading.Lock()

lock = threading.Lock()
counter = 0

def increment():
global counter
for _ in range(1000000):
with lock:
counter += 1 # Now safe

threads = [threading.Thread(target=increment) for _ in range(5)]

for t in threads:
t.start()
for t in threads:
t.join()

print("Final counter value:", counter) # Correct: 5,000,000

B. Global Variable Not Updating Across Threads

Sometimes, threads seem unable to update a global variable correctly.

Example (Unexpected Behavior)

import threading

flag = False # Global variable

def worker():
global flag
flag = True # Change not always visible in other threads

t = threading.Thread(target=worker)
t.start()
t.join()

print("Flag:", flag) # Expected: True | Actual: Sometimes False!

Issue: Due to caching optimizations, a thread may read a stale version of the global variable.

Fix: Use threading.Event() to safely share state

event = threading.Event()

def worker():
event.set() # This safely updates the flag

t = threading.Thread(target=worker)
t.start()
t.join()

print("Flag:", event.is_set()) # Always True

C. Inconsistent Data Due to Shared List or Dictionary

Modifying shared lists or dictionaries without locks can cause data corruption.

Example (Unexpected Behavior)

import threading

data = []

def add_item():
for _ in range(1000):
data.append(1) # Multiple threads modifying the list

threads = [threading.Thread(target=add_item) for _ in range(5)]

for t in threads:
t.start()
for t in threads:
t.join()

print("List length:", len(data)) # Expected: 5000 | Actual: Unpredictable!

Issue: Threads may overwrite or skip writes, leading to inconsistent data.

Fix: Use threading.Lock()

lock = threading.Lock()
data = []

def add_item():
for _ in range(1000):
with lock:
data.append(1) # Now thread-safe

threads = [threading.Thread(target=add_item) for _ in range(5)]

for t in threads:
t.start()
for t in threads:
t.join()

print("List length:", len(data)) # Correct: 5000

2. Summary of Fixes

IssueFix
Race conditions (global variable modified by multiple threads)Use threading.Lock()
Global variable not updating correctlyUse threading.Event()
Shared lists/dictionaries getting corruptedUse threading.Lock()

Leave a Reply

Your email address will not be published. Required fields are marked *