When deadlocks share multiple resources between threads, if the two threads occupy a part of resources and wait for the resources of the other side at the same time, the deadlock will occur. Although deadlocks rarely occur, once they happen, they will be deadlocked.
When multiple resources are shared between threads, if the two threads occupy a part of resources and wait for the resources of the other side at the same time, a deadlock will occur. Although deadlocks rarely occur, once they occur, the application will stop responding. The following is an example of a deadlock:
# encoding: UTF-8import threadingimport time class MyThread(threading.Thread): def do1(self): global resA, resB if mutexA.acquire(): msg = self.name+' got resA' print msg if mutexB.acquire(1): msg = self.name+' got resB' print msg mutexB.release() mutexA.release() def do2(self): global resA, resB if mutexB.acquire(): msg = self.name+' got resB' print msg if mutexA.acquire(1): msg = self.name+' got resA' print msg mutexA.release() mutexB.release() def run(self): self.do1() self.do2()resA = 0resB = 0 mutexA = threading.Lock()mutexB = threading.Lock() def test(): for i in range(5): t = MyThread() t.start()if __name__ == '__main__': test()
Execution result:
Thread-1 got resA
Thread-1 got resB
Thread-1 got resB
Thread-1 got resA
Thread-2 got resA
Thread-2 got resB
Thread-2 got resB
Thread-2 got resA
Thread-3 got resA
Thread-3 got resB
Thread-3 got resB
Thread-3 got resA
Thread-5 got resA
Thread-5 got resB
Thread-5 got resB
Thread-4 got resA
At this time, the process has died.
Reentrant lock
A simpler deadlock occurs when a thread "iterates" to request the same resource, which directly causes a deadlock:
import threadingimport 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.acquire() mutex.release() mutex.release()num = 0mutex = threading.Lock()def test(): for i in range(5): t = MyThread() t.start()if __name__ == '__main__': test()
To support multiple requests to the same resource in the same thread, python provides the "reentrant lock": threading. RLock. RLock internally maintains a Lock and a counter variable. counter records the number of acquire times so that resources can be require multiple times. Resources can be obtained only when all acquire of a thread is release. In the above example, if you use RLock instead of Lock, no deadlock will occur:
import threadingimport 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.acquire() mutex.release() mutex.release()num = 0mutex = threading.RLock()def test(): for i in range(5): t = MyThread() t.start()if __name__ == '__main__': test()
Execution result:
Thread-1 set num to 1
Thread-3 set num to 2
Thread-2 set num to 3
Thread-5 set num to 4
Thread-4 set num to 5