一 死鎖現象
所謂死鎖:是指兩個或兩個以上的進程或線程在執行過程中,因爭奪資源而造成的一種互相等待的現象,若無外力作用,它們都將無法推進下去。此時稱系統處于死鎖狀態或系統產生了死鎖,這些永遠在互相等待的進程稱為死鎖進程,如下就是死鎖
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 | from ?threading? import ?Thread, Lock import ?time mutexA? = ?Lock() mutexB? = ?Lock() class ?MyThread(Thread): ???? def ?run( self ): ???????? self .func1() ???????? self .func2() ???? def ?func1( self ): ???????? mutexA.acquire() ???????? print ( '\033[41m%s 拿到A鎖\033[0m' ?% ?self .name) ???????? mutexB.acquire() ???????? print ( '\033[42m%s 拿到B鎖\033[0m' ?% ?self .name) ???????? mutexB.release() ???????? mutexA.release() ???? def ?func2( self ): ???????? mutexB.acquire() ???????? print ( '\033[43m%s 拿到B鎖\033[0m' ?% ?self .name) ???????? time.sleep( 3 ) ???????? mutexA.acquire() ???????? print ( '\033[44m%s 拿到A鎖\033[0m' ?% ?self .name) ???????? mutexA.release() ???????? mutexB.release() ???? ? if ?__name__? = = ?'__main__' : ???? for ?i? in ?range ( 10 ): ???????? t? = ?MyThread() ???????? t.start() |
執行效果
1 2 3 4 | Thread - 1 ?拿到A鎖 Thread - 1 ?拿到B鎖 Thread - 1 ?拿到B鎖 Thread - 2 ?拿到A鎖???????? # 出現死鎖,整個程序阻塞 |
二 遞歸鎖
解決方法,遞歸鎖,在Python中為了支持在同一線程中多次請求同一資源,Python提供了可重入鎖RLock
這個RLock內部維護著一個Lock和一個counter變量,counter記錄了acquire的次數,從而使得資源可以被多次require。直到一個線程所有的acquire都被release,其它的線程才能獲得資源。上面的例子如果使用RLock代替Lock,則不會發生死鎖,二者的區別是:遞歸鎖可以連續acquire多次,而互斥鎖只能acquire一次
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 | # 遞歸鎖 from ?threading? import ?Thread, RLock import ?time mutexA? = ?mutexB? = ?RLock()??????? # 一個線程拿到鎖,counter加1,該線程內又碰到加鎖的情況,則counter繼續加1,這期間所有其他線程都只能等待,等待該線程釋放所有鎖,即counter遞減到0為止 class ?MyThread(Thread): ???? def ?run( self ): ???????? self .func1() ???????? self .func2() ???????? ? ???? def ?func1( self ): ???????? mutexA.acquire() ???????? print ( '\033[41m%s 拿到A鎖\033[0m' ?% ?self .name) ???????? mutexB.acquire() ???????? print ( '%s 拿到B鎖' ?% ?self .name) ???????? mutexB.release() ???????? mutexA.release() ???? def ?func2( self ): ???????? mutexB.acquire() ???????? print ( '\033[43m%s 拿到B鎖\033[0m' ?% ?self .name) ???????? mutexA.acquire() ???????? print ( '%s 拿到A鎖' ?% ?self .name) ???????? mutexA.release() ???????? mutexB.release() if ?__name__? = = ?'__main__' : ???? for ?i? in ?range ( 10 ): ???????? t? = ?MyThread() ???????? t.start() |