pythonmultithreadinglanguage-lawyer

Is double-checked locking thread-safe in Python?


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?


Solution

  • 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!