pythonmultithreadingpython-multiprocessing

Lock classes and Threading in python for dict moifications


I was learning and testing threading in python, and Lock class, So in here I want to add a key to persons but let's say it will takes some time, in another thread I want to read the key. in first thread I should lock the process but I still get an error.

import threading
from time import sleep


persons = {
    "test": "test",
    "test2": "test2",
}
lock = threading.Lock()

def func1():
    global persons
    lock.acquire()
    sleep(10)
    persons["test3"] = "test3"
    lock.release()

def func2():
    global persons
    print(persons["test3"])

t1 = threading.Thread(target=func1)
t2 = threading.Thread(target=func2)

t1.start()
t2.start()

t2.join()
t1.join()

I lock the func1() but still get error:

Traceback (most recent call last):
  File "c:\Users\p.riahi\AppData\Local\Programs\Python\Python311\Lib\threading.py", line 1038, in _bootstrap_inner
    self.run()
  File "c:\Users\p.riahi\AppData\Local\Programs\Python\Python311\Lib\threading.py", line 975, in run
    self._target(*self._args, **self._kwargs)
  File "c:\Users\p.riahi\Desktop\temp\thred.py", line 20, in func2
    print(persons["test3"])
          ~~~~~~~^^^^^^^^^
KeyError: 'test3'

Can anyone help me what I misunderstand here, the func1() should have locked the persons but it's not.


Solution

  • If thread t2 runs before thread t1 acquires the lock and adds "test3", t2.join() might cause the main thread to wait for t2 to finish even though there's no "test3" key yet in the dictionary. This could lead to a KeyError exception.

    So, you should lock the person inside function2 and release it after read the person. I have modified the code, you can use it.

    import threading
    from time import sleep
    
    
    persons = {
        "test": "test",
        "test2": "test2",
    }
    lock = threading.Lock()
    
    def func1():
        global persons
        lock.acquire()
        sleep(10)
        persons["test3"] = "test3"
        lock.release()
    
    # def func2():
    #     global persons
    #     print(persons["test3"])
    def func2():
        global persons
        lock.acquire()
        try:
            value = persons["test3"]  # Attempt to get the value
            print(value)
        except KeyError:  # Handle case where key doesn't exist
            print("Key 'test3' not found in the dictionary")
        finally:
            lock.release()
    
    t1 = threading.Thread(target=func1)
    t2 = threading.Thread(target=func2)
    
    t1.start()
    t2.start()
    
    t2.join()
    t1.join()