死锁:指的是某个资源被占用后一直得不到释放,致使其余须要这个资源的线程或进程进入阻塞状态安全
状况一:对同一把互斥锁屡次执行acquire方法,将致使死锁多线程
from threading import Lock l = Lock() l.acquire() print('run....') # 打印run.... l.acquire() print('deadlock....') # 出现死锁,不打印
解决方法:首先这样写没有意义,其次在加锁时加上超时l.acquire(timeout=10)
,超出时间后继续执行,线程不会卡死并发
状况二:一个共享资源要访问必须同时具有多把锁,可是这些锁被不一样线程或进程所持有,就会致使线程或进程之间相互等待对方释放,从而致使进入阻塞状态ui
import time from threading import Lock, Thread A = Lock() B = Lock() class Mytask(Thread): def run(self): self.eat() self.sleep() def eat(self): A.acquire() time.sleep(1) print(f'{self.name} got A', time.ctime()) B.acquire() print(f'{self.name} got B', time.ctime()) B.release() A.release() def sleep(self): B.acquire() time.sleep(1) print(f'{self.name} got B', time.ctime()) A.acquire() print(f'{self.name} got A', time.ctime()) A.release() B.release() for i in range(10): t = Mytask() t.start() -------------------------------------------------------------------------- Thread-1 got A Sat Jul 6 20:37:47 2019 Thread-1 got B Sat Jul 6 20:37:47 2019 Thread-2 got A Sat Jul 6 20:37:48 2019 Thread-1 got B Sat Jul 6 20:37:48 2019 # 线程2抢到了A锁没抢到B锁,线程1抢到了B锁没抢到A锁。线程2等线程1释放B锁,线程1等线程2释放A锁,双方互相等待,形成死锁现象
解决方法:1.抢锁必定按照相同的顺序去抢,2.给抢锁加上超时,若是超时则放弃执行线程
在Python中为了支持在同一线程中屡次请求同一资源,python提供了可重入锁RLock。这个RLock内部维护着一个Lock和一个counter变量,counter记录了acquire的次数,从而使得资源能够被屡次require。直到一个线程全部的acquire都被release,其余的线程才能得到资源。上面的例子若是使用RLock代替Lock,则不会发生死锁:code
import time from threading import RLock, Thread R = RLock() class Mytask(Thread): def run(self): self.eat() self.sleep() def eat(self): R.acquire() time.sleep(1) print(f'{self.name} got A', time.ctime()) R.release() def sleep(self): R.acquire() time.sleep(1) print(f'{self.name} got B', time.ctime()) R.release() for i in range(10): t = Mytask() t.start()
与互斥锁的区别:多线程之间都有互斥的效果,不一样在于递归锁能够对这个锁执行屡次acquire递归
能够限制同时并发执行公共代码的线程数量,若是限制数量为1则与普通互斥锁没有区别。并不能用来解决安全问题,而是用来限制最大的并发量进程
from threading import Semaphore, currentThread, Thread def task(): s.acquire() print('hello world') time.sleep(2) s.release() s = Semaphore(3) # 限制线程的并发数,不设置默认为1 for i in range(10): t = Thread(target=task) t.start()