亚洲免费在线-亚洲免费在线播放-亚洲免费在线观看-亚洲免费在线观看视频-亚洲免费在线看-亚洲免费在线视频

舉例講解Python中的死鎖、可重入鎖和互斥鎖

系統 1969 0

一、死鎖

簡單來說,死鎖是一個資源被多次調用,而多次調用方都未能釋放該資源就會造成死鎖,這里結合例子說明下兩種常見的死鎖情況。

1、迭代死鎖

該情況是一個線程“迭代”請求同一個資源,直接就會造成死鎖:

            
import threading
import time
class MyThread(threading.Thread):
  def run(self):
    global num
    time.sleep(1)
    if mutex.acquire(1):
      num = num+1
      msg = self.name+' set num to '+str(num)
      print msg
      mutex.acquire()
      mutex.release()
      mutex.release()
num = 0
mutex = threading.Lock()
def test():
  for i in range(5):
    t = MyThread()
    t.start()
if __name__ == '__main__':
  test()

          

上例中,在run函數的if判斷中第一次請求資源,請求后還未 release ,再次acquire,最終無法釋放,造成死鎖。這里例子中通過將print下面的兩行注釋掉就可以正常執行了 ,除此之外也可以通過可重入鎖解決,后面會提到。

2、互相調用死鎖

上例中的死鎖是在同一個def函數內多次調用造成的,另一種情況是兩個函數中都會調用相同的資源,互相等待對方結束的情況。如果兩個線程分別占有一部分資源并且同時等待對方的資源,就會造成死鎖。

            
import threading
import time
class MyThread(threading.Thread):
  def do1(self):
    global resA, resB
    if mutexA.acquire():
       msg = self.name+' got resA'
       print msg
       if mutexB.acquire(1):
         msg = self.name+' got resB'
         print msg
         mutexB.release()
       mutexA.release()
  def do2(self):
    global resA, resB
    if mutexB.acquire():
       msg = self.name+' got resB'
       print msg
       if mutexA.acquire(1):
         msg = self.name+' got resA'
         print msg
         mutexA.release()
       mutexB.release()
  def run(self):
    self.do1()
    self.do2()
resA = 0
resB = 0
mutexA = threading.Lock()
mutexB = threading.Lock()
def test():
  for i in range(5):
    t = MyThread()
    t.start()
if __name__ == '__main__':
  test()

          

這個死鎖的示例稍微有點復雜。具體可以理下。

二、可重入鎖

為了支持在同一線程中多次請求同一資源,python提供了“可重入鎖”:threading.RLock。RLock內部維護著一個Lock和一個counter變量,counter記錄了acquire的次數,從而使得資源可以被多次require。直到一個線程所有的acquire都被release,其他的線程才能獲得資源。這里以例1為例,如果使用RLock代替Lock,則不會發生死鎖:

            
import threading
import time
class MyThread(threading.Thread):
  def run(self):
    global num
    time.sleep(1)
    if mutex.acquire(1):
      num = num+1
      msg = self.name+' set num to '+str(num)
      print msg
      mutex.acquire()
      mutex.release()
      mutex.release()
num = 0
mutex = threading.RLock()
def test():
  for i in range(5):
    t = MyThread()
    t.start()
if __name__ == '__main__':
  test()

          

和上面那個例子的不同之處在于threading.Lock()換成了threading.RLock() 。

三、互斥鎖
python threading模塊有兩類鎖:互斥鎖(threading.Lock )和可重用鎖(threading.RLock)。兩者的用法基本相同,具體如下:

            
lock = threading.Lock()
lock.acquire()
dosomething……
lock.release()

          

RLock的用法是將threading.Lock()修改為threading.RLock()。便于理解,先來段代碼:

            
[root@361way lock]# cat lock1.py

          
            
#!/usr/bin/env python
# coding=utf-8
import threading              # 導入threading模塊
import time               # 導入time模塊
class mythread(threading.Thread):    # 通過繼承創建類
  def __init__(self,threadname):   # 初始化方法
    # 調用父類的初始化方法
    threading.Thread.__init__(self,name = threadname)
  def run(self):             # 重載run方法
    global x         # 使用global表明x為全局變量
    for i in range(3):
      x = x + 1
    time.sleep(5)     # 調用sleep函數,讓線程休眠5秒
    print x
tl = []               # 定義列表
for i in range(10):
  t = mythread(str(i))        # 類實例化
  tl.append(t)           # 將類對象添加到列表中
x=0                 # 將x賦值為0
for i in tl:
  i.start() 

          

這里執行的結果和想想的不同,結果如下:

            
[root@361way lock]# python lock1.py

          
            
30
30
30
30
30
30
30
30
30
30

          

為什么結果都是30呢?關鍵在于global 行和 time.sleep行。

1、由于x是一個全局變量,所以每次循環后 x 的值都是執行后的結果值;

2、由于該代碼是多線程的操作,所以在sleep 等待的時候,之前已經執行完成的線程會在這等待,而后續的進程在等待的5秒這段時間也執行完成 ,等待print。同樣由于global 的原理,x被重新斌值。所以打印出的結果全是30 ;

3、便于理解,可以嘗試將sleep等注釋,你再看下結果,就會發現有不同。

在實際應用中,如抓取程序等,也會出現類似于sleep等待的情況。在前后調用有順序或打印有輸出的時候,就會現并發競爭,造成結果或輸出紊亂。這里就引入了鎖的概念,上面的代碼修改下,如下:

            
[root@361way lock]# cat lock2.py

          
            
#!/usr/bin/env python
# coding=utf-8
import threading              # 導入threading模塊
import time               # 導入time模塊
class mythread(threading.Thread):          # 通過繼承創建類
  def __init__(self,threadname):         # 初始化方法
    threading.Thread.__init__(self,name = threadname)
  def run(self):             # 重載run方法
    global x            # 使用global表明x為全局變量
    lock.acquire()           # 調用lock的acquire方法
    for i in range(3):
      x = x + 1
    time.sleep(5)      # 調用sleep函數,讓線程休眠5秒
    print x
    lock.release()        # 調用lock的release方法
lock = threading.Lock()        # 類實例化
tl = []             # 定義列表
for i in range(10):
  t = mythread(str(i))      # 類實例化
  tl.append(t)       # 將類對象添加到列表中
x=0            # 將x賦值為0
for i in tl:
  i.start()           # 依次運行線程

          

執行的結果如下:

            
[root@361way lock]# python lock2.py

          
            
3
6
9
12
15
18
21
24
27
30

          

加鎖的結果會造成阻塞,而且會造成開鎖大。會根據順序由并發的多線程按順序輸出,如果后面的線程執行過快,需要等待前面的進程結束后其才能結束 --- 寫的貌似有點像隊列的概念了 ,不過在加鎖的很多場景下確實可以通過隊列去解決。


更多文章、技術交流、商務合作、聯系博主

微信掃碼或搜索:z360901061

微信掃一掃加我為好友

QQ號聯系: 360901061

您的支持是博主寫作最大的動力,如果您喜歡我的文章,感覺我的文章對您有幫助,請用微信掃描下面二維碼支持博主2元、5元、10元、20元等您想捐的金額吧,狠狠點擊下面給點支持吧,站長非常感激您!手機微信長按不能支付解決辦法:請將微信支付二維碼保存到相冊,切換到微信,然后點擊微信右上角掃一掃功能,選擇支付二維碼完成支付。

【本文對您有幫助就好】

您的支持是博主寫作最大的動力,如果您喜歡我的文章,感覺我的文章對您有幫助,請用微信掃描上面二維碼支持博主2元、5元、10元、自定義金額等您想捐的金額吧,站長會非常 感謝您的哦?。。?/p>

發表我的評論
最新評論 總共0條評論
主站蜘蛛池模板: www.奇米第四色 | 国产福利免费观看 | 久久精品全国免费观看国产 | 奇米影视777777 | 99热久久国产这里有只有精品 | 西西做人爱免费视频 | 国产手机在线精品 | 色射色 | 亚洲精品自拍视频 | 五月婷婷伊人网 | 99热精品6 | 天天干夜夜骑 | 日韩免费片 | 美女视频很黄很黄又免费的 | 欧美成人精品久久精品 | 干成人| 日韩毛片| 成人国产精品一区二区网站 | 四虎海外在线永久免费看 | 国产一区二区三区在线视频 | 日韩一级不卡 | 久久的爱久久久久的快乐 | 妖精视频永久在线入口 | 欧美亚洲综合网 | 久久青草免费97线频观 | 4虎影院午夜在线观看 | 亚洲激情视频在线播放 | 97国内免费久久久久久久久久 | 99精品这里只有精品高清视频 | 国产精品女仆装在线播放 | 欧美亚洲国产色综合 | xxxx免费观看 | 五月婷激情 | 五月激情五月婷婷 | 国产99在线 | 亚洲 | 天天躁狠狠躁狠狠躁夜夜躁 | se视频在线 | 国内自拍 在线播放 网红 | 久久成人亚洲香蕉草草 | 国产精品久久久久久久午夜片 | 午夜视频在线免费看 |