Python multithreaded programming (iv) : use the Lock mutex

  • 2020-05-05 11:25:36
  • OfStack

It has already been demonstrated Python: use threading module implement multithreaded programming 2 two ways up threads and Python: use threading module implement multithreaded programming three threading. Thread class important function of these two articles are example demonstrates unrelated independent thread, we now consider such a question: suppose each thread need access to the same public resources, how to write our code?


'''
Created on 2012-9-8
 
@author: walfred
@module: thread.ThreadTest3
''' 
import threading 
import time 
 
counter = 0 
 
class MyThread(threading.Thread): 
    def __init__(self): 
        threading.Thread.__init__(self) 
 
    def run(self): 
        global counter 
        time.sleep(1); 
        counter += 1 
        print "I am %s, set counter:%s" % (self.name, counter) 
 
if __name__ == "__main__": 
    for i in range(0, 200): 
        my_thread = MyThread() 
        my_thread.start()

To solve the above problem, we might write code like this. Let's say we run 200 threads, but all 200 threads will access the common counter resource and process it (counter += 1). The code looks like this, but let's look at the result:


I am Thread-69, set counter:64
I am Thread-73, set counter:66I am Thread-74, set counter:67I am Thread-75, set counter:68I am Thread-76, set counter:69I am Thread-78, set counter:70I am Thread-77, set counter:71I am Thread-58, set counter:72I am Thread-60, set counter:73I am Thread-62, set counter:74I am Thread-66,set counter:75I am Thread-70, set counter:76I am Thread-72, set counter:77I am Thread-79, set counter:78I am Thread-71, set counter:78

I have only posted part of the printed result, from which we have seen that the global resource (counter) is preempted. The reason for the problem is that there is no control over the access of multiple threads to the same resource, which causes damage to the data and makes the results of the thread running unpredictable. This phenomenon is called "thread insecurity". In the development process we have to avoid this situation, so how to avoid? This brings us to the mutex we mentioned in our review.

The mutex concept

In Python programming, the concept of object mutex is introduced to ensure the integrity of Shared data operations. Each object corresponds to a marker called a mutex, which ensures that only one thread can access the object at any one time. In Python we use the Lock class provided by the threading module.

We modified the above program by adding a mutex variable mutex = threading.Lock (), and then we would grab the lock mutex.acquire () before fighting for the resource, and then release the lock mutex.release () after using the resource. The code is as follows:


'''
Created on 2012-9-8
 
@author: walfred
@module: thread.ThreadTest4
''' 
 
import threading 
import time 
 
counter = 0 
mutex = threading.Lock() 
 
class MyThread(threading.Thread): 
    def __init__(self): 
        threading.Thread.__init__(self) 
 
    def run(self): 
        global counter, mutex 
        time.sleep(1); 
        if mutex.acquire(): 
            counter += 1 
            print "I am %s, set counter:%s" % (self.name, counter) 
            mutex.release() 
 
if __name__ == "__main__": 
    for i in range(0, 100): 
        my_thread = MyThread() 
        my_thread.start()

synchronous blocking

When a thread calls the acquire() method of the Lock object to obtain a lock, the lock enters the "locked" state. Because only one thread at a time can acquire the lock, if another thread 2 tries to acquire the lock at this time, that thread 2 will become "blo synchronous blocked. Until the release() method of the lock is released by the thread 1 that owns the lock, the lock enters the "unlocked" state. The thread scheduler selects one of the threads in the synchronously blocked state to acquire the lock and put the thread into the run (running) state.

further considers

By using a mutex on a common resource, this simply achieves our goal, but if we run into the following situation:

What do I do when I encounter lock nesting, which is when one thread needs to fetch a critical resource again;
If there are multiple common resources, when threads share multiple resources, if two threads occupy a part of the resource and wait for the other's resource at the same time;

Both of these situations directly cause the program to hang, which is deadlock, and we will talk about deadlocks and reentrapable locks RLock.


Related articles: