Python threading. How do I lock a thread?

PythonMultithreading

Python Problem Overview


I'm trying to understand the basics of threading and concurrency. I want a simple case where two threads repeatedly try to access one shared resource.

The code:

import threading

class Thread(threading.Thread):
    def __init__(self, t, *args):
        threading.Thread.__init__(self, target=t, args=args)
        self.start()
count = 0
lock = threading.Lock()

def increment():
    global count 
    lock.acquire()
    try:
        count += 1    
    finally:
        lock.release()
   
def bye():
    while True:
        increment()
        
def hello_there():
    while True:
        increment()

def main():    
    hello = Thread(hello_there)
    goodbye = Thread(bye)
    
    while True:
        print count

if __name__ == '__main__':
    main()

So, I have two threads, both trying to increment the counter. I thought that if thread 'A' called increment(), the lock would be established, preventing 'B' from accessing until 'A' has released.

Running the makes it clear that this is not the case. You get all of the random data race-ish increments.

How exactly is the lock object used?

Additionally, I've tried putting the locks inside of the thread functions, but still no luck.

Python Solutions


Solution 1 - Python

You can see that your locks are pretty much working as you are using them, if you slow down the process and make them block a bit more. You had the right idea, where you surround critical pieces of code with the lock. Here is a small adjustment to your example to show you how each waits on the other to release the lock.

import threading
import time
import inspect

class Thread(threading.Thread):
    def __init__(self, t, *args):
        threading.Thread.__init__(self, target=t, args=args)
        self.start()

count = 0
lock = threading.Lock()

def incre():
    global count
    caller = inspect.getouterframes(inspect.currentframe())[1][3]
    print "Inside %s()" % caller
    print "Acquiring lock"
    with lock:
        print "Lock Acquired"
        count += 1  
        time.sleep(2)  

def bye():
    while count < 5:
        incre()

def hello_there():
    while count < 5:
        incre()

def main():    
    hello = Thread(hello_there)
    goodbye = Thread(bye)


if __name__ == '__main__':
    main()

Sample output:

...
Inside hello_there()
Acquiring lock
Lock Acquired
Inside bye()
Acquiring lock
Lock Acquired
...

Solution 2 - Python

import threading 
  
# global variable x 
x = 0
  
def increment(): 
    """ 
    function to increment global variable x 
    """
    global x 
    x += 1
  
def thread_task(): 
    """ 
    task for thread 
    calls increment function 100000 times. 
    """
    for _ in range(100000): 
        increment() 
  
def main_task(): 
    global x 
    # setting global variable x as 0 
    x = 0
  
    # creating threads 
    t1 = threading.Thread(target=thread_task) 
    t2 = threading.Thread(target=thread_task) 
  
    # start threads 
    t1.start() 
    t2.start() 
  
    # wait until threads finish their job 
    t1.join() 
    t2.join() 
  
if __name__ == "__main__": 
    for i in range(10): 
        main_task() 
        print("Iteration {0}: x = {1}".format(i,x))

Attributions

All content for this solution is sourced from the original question on Stackoverflow.

The content on this page is licensed under the Attribution-ShareAlike 4.0 International (CC BY-SA 4.0) license.

Content TypeOriginal AuthorOriginal Content on Stackoverflow
QuestionZackView Question on Stackoverflow
Solution 1 - PythonjdiView Answer on Stackoverflow
Solution 2 - Pythonfunny guru992View Answer on Stackoverflow