The double-checked locking idiom is not reliable in some languages, and I want to know whether Python is one of them. More concretely, is the following code...
# Objects shared by threads:
obj = None
lock_for_obj = threading.Lock()
def get_obj():
"""Function called concurrently by threads."""
if obj is None:
with lock_for_obj:
if obj is None:
obj = factory() # Never returns `None`
return obj
...thread-safe in Python? Are there scenarios/implementations where it is/isn't? Why?
Of course I know I'm jumping in on a 6 years old question š but it's the only one I found in SO. I found this How the GIL Works Under the Hood
Thread Switching: Python schedules threads and switches them based on a specific frequency, typically every 5 milliseconds (the ācheck intervalā).
and now I think the DCL idiom is not thread-safe in Python at all. In the example of the OP the statement
obj = factory()
, assuming the CPython compiled code (a sensible assumption I think) does optimization and instruction reordering, can break down to the following sub-steps:
t0: create new factory() object
t1: place address into `obj`
t2: initialize object by executing `factory.__init__()`
t3: `factory.__init__()` completed and `obj` is fully initialized
and even in the presence of the GIL, the DCL idiom can break, if the thread switch to Thread 2 occurred at t2. Now Thread 2 calls get_obj()
and the first if obj is None
is False
so get_obj()
returns obj
which is not yet initialized -- disaster!