Home  >  Article  >  Backend Development  >  Python multi-threaded programming 3: Using mutex locks to synchronize threads

Python multi-threaded programming 3: Using mutex locks to synchronize threads

高洛峰
高洛峰Original
2016-10-18 11:33:201232browse

Question raised

In the example in the previous section, each thread is independent of each other and has no relationship with each other. Now assume an example: there is a global count num, each thread gets this global count, performs some processing based on num, and then adds 1 to num. It is easy to write code like this:

# encoding: UTF-8
import threading
import time
  
class MyThread(threading.Thread):
    def run(self):
        global num
        time.sleep(1)
        num = num+1
        msg = self.name+' set num to '+str(num)
        print msg
num = 0
def test():
    for i in range(5):
        t = MyThread()
        t.start()
if __name__ == '__main__':
    test()

But the running result is incorrect:


Thread-5 set num to 2

Thread-3 set num to 3

Thread-2 set num to 5

Thread-1 set num to 5

Thread-4 set num to 4


The reason for the problem is that the access of multiple threads to the same resource is not controlled, causing damage to the data and making the results of thread operation unpredictable. . This phenomenon is called "thread unsafe".

Mutex lock synchronization

The above example leads to the most common problem of multi-threaded programming: data sharing. When multiple threads modify a certain shared data, synchronization control is required.

Thread synchronization can ensure that multiple threads safely access competing resources. The simplest synchronization mechanism is to introduce a mutex lock. A mutex introduces a state to a resource: locked/unlocked. When a thread wants to change shared data, it must first lock it. At this time, the status of the resource is "locked" and other threads cannot change it; until the thread releases the resource and changes the status of the resource to "unlocked", other threads can Lock the resource again. The mutex lock ensures that only one thread performs writing operations at a time, thereby ensuring the correctness of data in multi-threaded situations.

The Lock class is defined in the threading module, which can handle locking conveniently:

#Create lock

mutex = threading.Lock()

#Lock

mutex.acquire([timeout])

#Release

mutex.release()

Among them, the lock method acquire can have an optional parameter timeout with a timeout period. If a timeout is set, the return value can be used to determine whether the lock is obtained after the timeout, so that some other processing can be performed.

The code to implement the above example using a mutex is as follows:

import threading
import time
  
class MyThread(threading.Thread):
    def run(self):
        global num
        time.sleep(1)
  
        if mutex.acquire(1): 
            num = num+1
            msg = self.name+' set num to '+str(num)
            print msg
            mutex.release()
num = 0
mutex = threading.Lock()
def test():
    for i in range(5):
        t = MyThread()
        t.start()
if __name__ == '__main__':
    test()

Running results:


Thread-3 set num to 1

Thread-4 set num to 2

Thread-5 set num to 3

Thread-2 set num to 4

Thread-1 set num to 5

You can see that after adding the mutex lock, the running results are in line with expectations.

Synchronous blocking

When a thread calls the acquire() method of the lock to acquire the lock, the lock enters the "locked" state. Only one thread can obtain the lock at a time. If another thread attempts to obtain the lock at this time, the thread will become "blocked", which is called "synchronous blocking" (see the basic concept of multi-threading).

Until the thread owning the lock calls the release() method of the lock to release the lock, the lock enters the "unlocked" state. The thread scheduler selects one of the threads in the synchronous blocking state to obtain the lock and makes the thread enter the running state.

The most basic contents of mutex locks are these. The next section will discuss reentrant locks (RLock) and deadlock issues.


Statement:
The content of this article is voluntarily contributed by netizens, and the copyright belongs to the original author. This site does not assume corresponding legal responsibility. If you find any content suspected of plagiarism or infringement, please contact admin@php.cn