舉例講解 Python 中的死鎖、可重入鎖和互斥鎖
簡單來說,死鎖是一個資源被多次呼叫,而多次呼叫方都未能釋放該資源就會造成死鎖,這裡結合例子說明下兩種常見的死鎖情況。
1、迭代死鎖
該情況是一個執行緒“迭代”請求同一個資源,直接就會造成死鎖:
Python123456789101112131415161718192021 | importthreadingimporttimeclassMyThread(threading.Thread):defrun(self):globalnumtime.sleep(1)ifmutex.acquire(1):num=num+1msg=self.name+' set num to '+str(num)printmsgmutex.acquire()mutex.release()mutex.release()num=0mutex=threading |
上例中,在run函式的if判斷中第一次請求資源,請求後還未 release ,再次acquire,最終無法釋放,造成死鎖。這裡例子中通過將print下面的兩行註釋掉就可以正常執行了 ,除此之外也可以通過可重入鎖解決,後面會提到。
2、互相呼叫死鎖
上例中的死鎖是在同一個def函式內多次呼叫造成的,另一種情況是兩個函式中都會呼叫相同的資源,互相等待對方結束的情況。如果兩個執行緒分別佔有一部分資源並且同時等待對方的資源,就會造成死鎖。
123456789101112131415161718192021222324252627282930313233343536 | importthreadingimporttimeclassMyThread(threading.Thread):defdo1(self):globalresA,resBifmutexA.acquire():msg=self.name+' got resA'printmsgifmutexB.acquire(1):msg=self.name+' got resB'printmsgmutexB.release()mutexA.release()defdo2(self):globalresA,resBifmutexB.acquire():msg=self.name+' got resB'printmsgifmutexA.acquire(1):msg=self.name+' got resA'printmsgmutexA.release()mutexB.release()defrun(self):self.do1()self.do2()resA=0resB=0mutexA=threading.Lock()mutexB=threading.Lock()deftest():foriinrange(5):t=MyThread()t.start()if__name__=='__main__':test() |
這個死鎖的示例稍微有點複雜。具體可以理下。
二、可重入鎖
為了支援在同一執行緒中多次請求同一資源,python提供了“可重入鎖”:threading.RLock。RLock內部維護著一個Lock和一個counter變數,counter記錄了acquire的次數,從而使得資源可以被多次require。直到一個執行緒所有的acquire都被release,其他的執行緒才能獲得資源。這裡以例1為例,如果使用RLock代替Lock,則不會發生死鎖:
Python123456789101112131415161718192021 | importthreadingimporttimeclassMyThread(threading.Thread):defrun(self):globalnumtime.sleep(1)ifmutex.acquire(1):num=num+1msg=self.name+' set num to '+str(num)printmsgmutex.acquire()mutex.release()mutex.release()num=0mutex=threading.RLock()deftest():foriinrange(5):t=MyThread()t.start()if__name__=='__main__':test() |
和上面那個例子的不同之處在於threading.Lock()換成了threading.RLock() 。
三、互斥鎖
python threading模組有兩類鎖:互斥鎖(threading.Lock )和可重用鎖(threading.RLock)。兩者的用法基本相同,具體如下:
1234 | lock=threading.Lock()lock.acquire()dosomething……lock.release() |
RLock的用法是將threading.Lock()修改為threading.RLock()。便於理解,先來段程式碼:
1 | [root@361waylock]# cat lock1.py |
123456789101112131415161718192021 | #!/usr/bin/env python# coding=utf-8importthreading# 匯入threading模組importtime# 匯入time模組classmythread(threading.Thread):# 通過繼承建立類def__init__(self,threadname):# 初始化方法# 呼叫父類的初始化方法threading.Thread.__init__(self,name=threadname)defrun(self):# 過載run方法globalx# 使用global表明x為全域性變數foriinrange(3):x=x+1time.sleep(5)# 呼叫sleep函式,讓執行緒休眠5秒printxtl=[]# 定義列表foriinrange(10):t=mythread(str(i))# 類例項化tl.append(t)# 將類物件新增到列表中x=0# 將x賦值為0foriintl:i.start() |
這裡執行的結果和想想的不同,結果如下:
1 | [root@361waylock]# python lock1.py |
12345678910 | 30303030303030303030 |
為什麼結果都是30呢?關鍵在於global 行和 time.sleep行。
1、由於x是一個全域性變數,所以每次迴圈後 x 的值都是執行後的結果值;
2、由於該程式碼是多執行緒的操作,所以在sleep 等待的時候,之前已經執行完成的執行緒會在這等待,而後續的程序在等待的5秒這段時間也執行完成 ,等待print。同樣由於global 的原理,x被重新斌值。所以打印出的結果全是30 ;
3、便於理解,可以嘗試將sleep等註釋,你再看下結果,就會發現有不同。
在實際應用中,如抓取程式等,也會出現類似於sleep等待的情況。在前後呼叫有順序或列印有輸出的時候,就會現併發競爭,造成結果或輸出紊亂。這裡就引入了鎖的概念,上面的程式碼修改下,如下:
1 | [root@361waylock]# cat lock2.py |
1234567891011121314151617181920212223 | #!/usr/bin/env python# coding=utf-8importthreading# 匯入threading模組importtime# 匯入time模組classmythread(threading.Thread):# 通過繼承建立類def__init__(self,threadname):# 初始化方法threading.Thread.__init__(self,name=threadname)defrun(self):# 過載run方法globalx# 使用global表明x為全域性變數lock.acquire()# 呼叫lock的acquire方法foriinrange(3):x=x+1time.sleep(5)# 呼叫sleep函式,讓執行緒休眠5秒printxlock.release()# 呼叫lock的release方法lock=threading.Lock()# 類例項化tl=[]# 定義列表foriinrange(10):t=mythread(str(i))# 類例項化tl.append(t)
相關推薦舉例講解 Python 中的死鎖、可重入鎖和互斥鎖簡單來說,死鎖是一個資源被多次呼叫,而多次呼叫方都未能釋放該資源就會造成死鎖,這裡結合例子說明下兩種常見的死鎖情況。 1、迭代死鎖 該情況是一個執行緒“迭代”請求同一個資源,直接就會造成死鎖: Python import 鎖--自旋鎖、阻塞鎖、可重入鎖、悲觀鎖、樂觀鎖、讀寫鎖、偏向所、輕量級鎖、重量級鎖、鎖膨脹、物件鎖和類鎖參考:http://blog.csdn.net/a314773862/article/details/54095819 自旋鎖 自旋鎖可以使執行緒在沒有取得鎖的時候,不被掛起,而轉去執行一個空迴圈,(即所謂的自旋,就是自己執行空迴圈),若在若干個空迴圈後,執行緒如果可以獲得 不可重入鎖、可重入鎖的實現以及測試可重入鎖定義:執行緒去請求自己擁有的鎖可請求到interface SelfDefineLock{ void lock(); void unlock(); } class Father{ SelfDefineLock lock; Father(SelfDefineLo Python中的可變、不可變對象和賦值技巧序列解包lis 我們 最大 pac 唯一標識 src 技術分享 efault pre 可變對象和不可變對象 在python中一切皆對象。在Python中不存在所謂的值傳遞調用,一切傳遞都是對象的引用,也可認為是傳址。 python中,對象分為可變(mutable)和不可變(imm 初探併發程式設計(一)AtomicInteger、Volatile關鍵字、可重入鎖1:為什麼要引入AtomicInteger關鍵字 在java中,多個執行緒訪問一個共享變數時會發生執行緒安全問題。 例子: Count類: 主函式開三個執行緒: Java 中15種鎖的介紹:公平鎖,可重入鎖,獨享鎖,互斥鎖,樂觀鎖,分段鎖,自旋鎖等等Java 中15種鎖的介紹 在讀很多併發文章中,會提及各種各樣鎖如公平鎖,樂觀鎖等等,這篇文章介紹各種鎖的分類。介紹的內容如下: 公平鎖 / 非公平鎖 可重入鎖 / 不可重入鎖 獨享鎖 / 共享鎖 互斥鎖 / 讀寫鎖 樂觀鎖 / 悲觀鎖 分段鎖 Java多執行緒01_可重入函式、可重入鎖測試環境 OS:windows7_X64 JDK:jdk1.8.0_20 IDE: eclipse_neon 一、可重入函式 相信很多人都聽說過可重入函式,可重入函式最重要的兩條法則就是: 只 java 自旋鎖(可重入且無死鎖)java自旋鎖 的實現原理:如果自旋鎖被另外一個執行緒物件持有,那麼當前獲取鎖的執行緒將陷入while迴圈等待,直到那個持有自旋鎖的執行緒物件釋放它所持有的自旋鎖,那麼那些想要獲取該自旋鎖的執行緒物件 將會有一個獲得該自旋鎖。 基於他這種原理,等待的時候,並不釋放cpu Signal處理中的函數可重入問題全局 ont alarm roman 軟件 p s 沖突 處理機 共享 1. Signal信號簡介信號是軟件層次上模擬的中斷,它是一種異步通信的處理機制。信號的異步性意味著,應用程序不用等待事件的發生,當信號發生時應用程序自動陷入到對應的信號處理函數中。產生信號的事件對進程 10-Synchronized:悲觀鎖,可重入鎖Synchronized:悲觀鎖,可重入鎖 特點:可重入的鎖 可重入鎖,一個獲得的鎖的執行緒沒執行完可以繼續獲得該鎖。 執行緒佔用鎖的時候,如果執行的同步程式碼出現異常,會自動將鎖讓出。 同步程式碼塊的程式碼是同步執行的(一次執行完),而非同步程 java synchronized內建鎖的可重入性《java併發程式設計實踐》一書中,關於synchronized內建鎖的可重入的例子如下: ------------------------------------------------------------------------------------------ JAVA鎖機制-可重入鎖,可中斷鎖,公平鎖,讀寫鎖,自旋鎖部落格引用處(以下內容在原有部落格基礎上進行補充或更改,謝謝這些大牛的部落格指導): JAVA鎖機制-可重入鎖,可中斷鎖,公平鎖,讀寫鎖,自旋鎖 在併發程式設計中,經常遇到多個執行緒訪問同一個 共享資源 ,這時候作為開發者必須考慮如何維護資料一致性,在java中synchronized Java 種15種鎖的介紹:公平鎖,可重入鎖,獨享鎖,互斥鎖等等...Java 中15種鎖的介紹 在讀很多併發文章中,會提及各種各樣鎖如公平鎖,樂觀鎖等等,這篇文章介紹各種鎖的分類。介紹的內容如下: 公平鎖 / 非公平鎖 可重入鎖 / 不可重入鎖 獨享鎖 / 共享鎖 互斥鎖 / 讀寫鎖 樂觀鎖 / 悲觀鎖 分段鎖 偏向 鎖——ReentrantReadWriteLock 可重入讀寫鎖ReentrantReadWriteLock 為可重入讀寫鎖,實現ReadWriteLock介面,他包含一個讀鎖(ReentrantReadWriteLock.ReadLock),一個寫鎖(ReentrantReadWriteLock.WriteLock),實現Lock介面。 鎖:可重入鎖 可中斷鎖 公平鎖 讀寫鎖轉自:http://www.cnblogs.com/wihainan/p/4762800.html 侵刪 1.可重入鎖 如果鎖具備可重入性,則稱作為可重入鎖。 像synchronized和ReentrantLock都是可重入鎖,可重入性在我看來實際上表明瞭鎖的分配機 Java 種15種鎖的介紹:公平鎖,可重入鎖,獨享鎖,互斥鎖等等Java 中15種鎖的介紹 在讀很多併發文章中,會提及各種各樣鎖如公平鎖,樂觀鎖等等,這篇文章介紹各種鎖的分類。介紹的內容如下 【分散式鎖】06-Zookeeper實現分散式鎖:可重入鎖原始碼分析前言 前面已經講解了Redis的客戶端Redission是怎麼實現分散式鎖的,大多都深入到原始碼級別。 在分散式系統中,常見的分散式鎖實現方案還有Zookeeper,接下來會深入研究Zookeeper是如何來實現分散式鎖的。 Zookeeper初識 檔案系統 Zookeeper維護一個類似檔案系統的資料結構 Linux可重入函式和執行緒安全的區別與聯絡(轉)*****可重入函式 函式被不同的控制流程呼叫,有可能在第一次呼叫還沒返回時就再次進入該函式,這稱為重入。 當程式執行到某一個函式的時候,可能因為硬體中斷或者異常而使得在使用者正在執行的程式 什麼是可重入函式和不可重入函式?1.可重入函式 在實時系統的設計中,經常會出現多個任務呼叫同一個函式的情況。如果這個函式不幸被設計成為不可重入的函式的話,那麼不同任務呼叫這個函式時可能修改其他任 務呼叫這個函式的資料,從而導致不可預料的後果。那麼什麼是可重入函式呢?所謂可重入是指一個可以被多個任務呼叫的過程,任務在呼叫時不必擔 malloc的可重入性和執行緒安全分析malloc函式是一個我們經常使用的函式,如果不對會造成一些潛在的問題。下面就malloc函式的執行緒安全性和可重入性做一些分析。 我們知道一個函式要做到執行緒安全,需要解決多個執行緒呼叫函式時訪問共享資源的衝突。而一個函式要做到可重入,需要不在函式內部使用靜態或全域性資料,不返回靜態或全域性資 |