python之死锁与递归锁
说到递归锁就要先说到死锁,下面给出死锁的定义:
在线程间共享多个资源的时候,如果俩个线程分别占有一部分资源并且同时等待对方的资源,就会造成死锁,因为系统判断这部分资源正在使用,所以这俩线程在无外力作用下将一直等待下去。
死锁代码示例:
import threading
import time
class MyThread(threading.Thread):
def actionA(self):
A.acquire()
print(self.name,'gotA',time.ctime())
time.sleep(2)
B.acquire()
print(self.name, 'gotB', time.ctime())
time.sleep(1)
B.release()
A.release()
def actionB(self):
B.acquire()
print(self.name, 'gotB', time.ctime())
time.sleep(2)
A.acquire()
print(self.name, 'gotA', time.ctime())
time.sleep(1)
A.release()
B.release()
def run(self):
self.actionA()
self.actionB()
if __name__ == '__main__':
A = threading.Lock()
B = threading.Lock()
L = []
for i in range(5):
t = MyThread()
t.start()
L.append(t)
for i in L:
i.join()
print('over........')
运行结果:
Thread-1 gotA Tue Aug 21 16:45:50 2018
Thread-1 gotB Tue Aug 21 16:45:52 2018
Thread-1 gotB Tue Aug 21 16:45:53 2018
Thread-2 gotA Tue Aug 21 16:45:53 2018
结果会卡在这儿,原因就是第一个线程执行完actionA后开始执行actionB,而第二个开始执行actionA,它们会对锁产生抢占,所以导致运行卡住形成死锁现象。
递归锁
针对threading.Lock()出现死锁现象,用到了递归锁threading.RLock()
特点:可以连续acquire()
递归锁代码改写:
import threading
import time
class MyThread(threading.Thread):
def actionA(self):
r_lock.acquire()
print(self.name,'gotA',time.ctime())
time.sleep(2)
r_lock.acquire()
print(self.name, 'gotB', time.ctime())
time.sleep(1)
r_lock.release()
r_lock.release()
def actionB(self):
r_lock.acquire()
print(self.name, 'gotB', time.ctime())
time.sleep(2)
r_lock.acquire()
print(self.name, 'gotA', time.ctime())
time.sleep(1)
r_lock.release()
r_lock.release()
def run(self):
self.actionA()
self.actionB()
if __name__ == '__main__':
# A = threading.Lock()
# B = threading.Lock()
r_lock = threading.RLock()
L = []
for i in range(5):
t = MyThread()
t.start()
L.append(t)
for i in L:
i.join()
print('over........')
运行结果:
Thread-1 gotA Tue Aug 21 17:10:43 2018
Thread-1 gotB Tue Aug 21 17:10:45 2018
Thread-2 gotA Tue Aug 21 17:10:46 2018
Thread-2 gotB Tue Aug 21 17:10:48 2018
Thread-2 gotB Tue Aug 21 17:10:49 2018
Thread-2 gotA Tue Aug 21 17:10:51 2018
Thread-4 gotA Tue Aug 21 17:10:52 2018
Thread-4 gotB Tue Aug 21 17:10:54 2018
Thread-5 gotA Tue Aug 21 17:10:55 2018
Thread-5 gotB Tue Aug 21 17:10:57 2018
Thread-5 gotB Tue Aug 21 17:10:58 2018
Thread-5 gotA Tue Aug 21 17:11:00 2018
Thread-3 gotA Tue Aug 21 17:11:01 2018
Thread-3 gotB Tue Aug 21 17:11:03 2018
Thread-3 gotB Tue Aug 21 17:11:04 2018
Thread-3 gotA Tue Aug 21 17:11:06 2018
Thread-1 gotB Tue Aug 21 17:11:07 2018
Thread-1 gotA Tue Aug 21 17:11:09 2018
Thread-4 gotB Tue Aug 21 17:11:10 2018
Thread-4 gotA Tue Aug 21 17:11:12 2018
over……..
递归锁的实质上RLock内部加了个计数器,获取一次acquire计数器就加个1,释放一次就减1,当计数器为0时,其他线程可以执行。
信号量(Semaphore)
信号量:
是用来控制线程并发数的,BoundeSemaphore 或Semaphore管理一个内置的计数器,每当调用acquire()时减一,调用release()时加一。计数器不能小于0,当计数器为0时,acquire将阻塞线程至同步锁定状态,直到其他线程调用release().(类似于停车位的概念)
BoundedSemaphore与Semaphore的唯一区别在于前者将在调用release时检查计数器的值是否超过计数器的初始值,如果超过了将抛出一个异常。
信号量代码示例:
import threading
import time
class myThread(threading.Thread):
def run(self):
if semaphore.acquire():
print(self.name)
time.sleep(5)
semaphore.release()
if __name__ == '__main__':
semaphore = threading.Semaphore(5)
thrs = []
for i in range(100):
thrs.append(myThread())
for t in thrs:
t.start()
运行结果是5次5次出现,每次停顿5秒。