Methods to avoid deadlock:
A deadlock occurs when two threads wait for each other to release resources. The Python interpreter does not monitor and will not actively take measures to deal with deadlock situations, so measures should be taken to avoid deadlocks when performing multi-threaded programming.
Once a deadlock occurs, the entire program will neither produce any exceptions nor give any prompts, but all threads will be blocked and unable to continue.
Deadlock is very easy to occur, especially when there are multiple synchronization monitors in the system, the following program will cause a deadlock:
import threading import time class A: def __init__(self): self.lock = threading.RLock() def foo(self, b): try: self.lock.acquire() print("当前线程名: " + threading.current_thread().name\ + " 进入了A实例的foo()方法" ) # ① time.sleep(0.2) print("当前线程名: " + threading.current_thread().name\ + " 企图调用B实例的last()方法") # ③ b.last() finally: self.lock.release() def last(self): try: self.lock.acquire() print("进入了A类的last()方法内部") finally: self.lock.release() class B: def __init__(self): self.lock = threading.RLock() def bar(self, a): try: self.lock.acquire() print("当前线程名: " + threading.current_thread().name\ + " 进入了B实例的bar()方法" ) # ② time.sleep(0.2) print("当前线程名: " + threading.current_thread().name\ + " 企图调用A实例的last()方法") # ④ a.last() finally: self.lock.release() def last(self): try: self.lock.acquire() print("进入了B类的last()方法内部") finally: self.lock.release() a = A() b = B() def init(): threading.current_thread().name = "主线程" # 调用a对象的foo()方法 a.foo(b) print("进入了主线程之后") def action(): threading.current_thread().name = "副线程" # 调用b对象的bar()方法 b.bar(a) print("进入了副线程之后") # 以action为target启动新线程 threading.Thread(target=action).start() # 调用init()函数 init()
Run the above program, it will See the effect shown in Figure 1.
Figure 1 Deadlock effect
As can be seen from Figure 1, the program can neither execute downward nor throw any Abnormal, it has been "stalemate". The reason is that the methods of object A and object B in the above program are both thread-safe methods.
There are two threads executing in the program. The thread execution body of the secondary thread is the action() function, and the thread execution body of the main thread is the init() function (the main program calls the init() function). In the action() function, let the B object call the bar() method, and in the init() function, let the A object call the foo() method.
Figure 1 shows that the action() function is executed first and calls the bar() method of the B object. Before entering the bar() method, the thread locks the Lock of the B object (when the program executes to No. 2 code, the secondary thread pauses for 0.2s); the CPU switches to executing another thread and lets the A object execute the foo() method, so you see that the main thread begins to execute the foo() method of the A instance. Before entering the foo() method, This thread locks the Lock of object A (when the program executes code ①, the main thread also pauses for 0.2s).
Next, the secondary thread will wake up first and continue to execute downwards until it reaches code ④ and hopes to call the last() method of the A object (before executing this method, the Lock of the A object must be first Lock), but at this time the main thread is maintaining the Lock of the A object, so the secondary thread is blocked.
The main thread should wake up next and continue to execute downwards until it reaches code ③ where it hopes to call the last() method of the B object (before executing this method, the B object must first be Lock), but at this time the secondary thread does not release the Lock of the B object.
At this point, it appears that the main thread holds the lock on object A and waits for object B to be locked, while the secondary thread holds the lock on object B and waits for object A to be locked. The two threads wait for each other. The lock is released first, so a deadlock occurs.
Deadlocks should not occur in programs. You should try to avoid deadlocks when writing programs. There are several common ways to solve the deadlock problem below:
Avoid multiple locks. Try to avoid locking multiple Locks on the same thread. For example, in the above deadlock program, the main thread needs to lock the Lock of two objects A and B, and the secondary thread also needs to lock the Lock of two objects A and B, which lays the hidden danger of deadlock.
has the same locking sequence. If multiple threads need to lock multiple Locks, they should ensure that they request locks in the same order. For example, in the above deadlock program, the main thread first locks the Lock of object A, and then locks the Lock of object B; while the secondary thread first locks the Lock of object B, and then locks the Lock of object A. This locking sequence can easily form nested locks, which can lead to deadlocks. This problem can be avoided if the main thread and the secondary thread lock in the same order.
Use timing lock. The program can specify the timeout parameter when calling the acquire() method to lock. This parameter specifies that the Lock will be automatically released after timeout seconds, so that the deadlock can be unlocked.
Deadlock detection. Deadlock detection is a deadlock prevention mechanism that relies on algorithmic mechanisms. It is mainly targeted at scenarios where sequential locking is impossible and timed locks cannot be used.
The above is the detailed content of How to avoid deadlock?. For more information, please follow other related articles on the PHP Chinese website!