死鎖:指的是某個資源被佔用後一直得不到釋放,致使其餘須要這個資源的線程或進程進入阻塞狀態安全
狀況一:對同一把互斥鎖屢次執行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()