Using a global dictionary with threads in Python

Is accessing/changing dictionary values thread-safe?

I have a global dictionary foo and multiple threads with ids id1, id2, ... , idn. Is it OK to access and change foo's values without allocating a lock for it if it's known that each thread will only work with its id-related value, say thread with id1 will only work with foo[id1]?

Answers 1

  • Assuming CPython: Yes and no. It is actually safe to fetch/store values from a shared dictionary in the sense that multiple concurrent read/write requests won't corrupt the dictionary. This is due to the global interpreter lock ("GIL") maintained by the implementation. That is:

    Thread A running:

    a = global_dict["foo"]
    

    Thread B running:

    global_dict["bar"] = "hello"
    

    Thread C running:

    global_dict["baz"] = "world"
    

    won't corrupt the dictionary, even if all three access attempts happen at the "same" time. The interpreter will serialize them in some undefined way.

    However, the results of the following sequence is undefined:

    Thread A:

    if "foo" not in global_dict:
       global_dict["foo"] = 1
    

    Thread B:

    global_dict["foo"] = 2
    

    as the test/set in thread A is not atomic ("time-of-check/time-of-use" race condition). So, it is generally best, if you lock things:

    from threading import RLock
    
    lock = RLock()
    
    def thread_A():
        lock.acquire()
        try:
            if "foo" not in global_dict:
                global_dict["foo"] = 1
        finally:
            lock.release()
    
    def thread_B():
        lock.acquire()
        try:
            global_dict["foo"] = 2
        finally:
            lock.release()
    

Related Articles