国产探花免费观看_亚洲丰满少妇自慰呻吟_97日韩有码在线_资源在线日韩欧美_一区二区精品毛片,辰东完美世界有声小说,欢乐颂第一季,yy玄幻小说排行榜完本

首頁(yè) > 編程 > Python > 正文

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

2019-11-25 17:03:01
字體:
供稿:網(wǎng)友

一、死鎖

簡(jiǎn)單來說,死鎖是一個(gè)資源被多次調(diào)用,而多次調(diào)用方都未能釋放該資源就會(huì)造成死鎖,這里結(jié)合例子說明下兩種常見的死鎖情況。

1、迭代死鎖

該情況是一個(gè)線程“迭代”請(qǐng)求同一個(gè)資源,直接就會(huì)造成死鎖:

import threadingimport timeclass 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 = 0mutex = threading.Lock()def test():  for i in range(5):    t = MyThread()    t.start()if __name__ == '__main__':  test()

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

2、互相調(diào)用死鎖

上例中的死鎖是在同一個(gè)def函數(shù)內(nèi)多次調(diào)用造成的,另一種情況是兩個(gè)函數(shù)中都會(huì)調(diào)用相同的資源,互相等待對(duì)方結(jié)束的情況。如果兩個(gè)線程分別占有一部分資源并且同時(shí)等待對(duì)方的資源,就會(huì)造成死鎖。

import threadingimport timeclass 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 = 0resB = 0mutexA = threading.Lock()mutexB = threading.Lock()def test():  for i in range(5):    t = MyThread()    t.start()if __name__ == '__main__':  test()

這個(gè)死鎖的示例稍微有點(diǎn)復(fù)雜。具體可以理下。

二、可重入鎖

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

import threadingimport timeclass 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 = 0mutex = threading.RLock()def test():  for i in range(5):    t = MyThread()    t.start()if __name__ == '__main__':  test()

和上面那個(gè)例子的不同之處在于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-8import threading              # 導(dǎo)入threading模塊import time               # 導(dǎo)入time模塊class mythread(threading.Thread):    # 通過繼承創(chuàng)建類  def __init__(self,threadname):   # 初始化方法    # 調(diào)用父類的初始化方法    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)     # 調(diào)用sleep函數(shù),讓線程休眠5秒    print xtl = []               # 定義列表for i in range(10):  t = mythread(str(i))        # 類實(shí)例化  tl.append(t)           # 將類對(duì)象添加到列表中x=0                 # 將x賦值為0for i in tl:  i.start() 

這里執(zhí)行的結(jié)果和想想的不同,結(jié)果如下:

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

為什么結(jié)果都是30呢?關(guān)鍵在于global 行和 time.sleep行。

1、由于x是一個(gè)全局變量,所以每次循環(huán)后 x 的值都是執(zhí)行后的結(jié)果值;

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

3、便于理解,可以嘗試將sleep等注釋,你再看下結(jié)果,就會(huì)發(fā)現(xiàn)有不同。

在實(shí)際應(yīng)用中,如抓取程序等,也會(huì)出現(xiàn)類似于sleep等待的情況。在前后調(diào)用有順序或打印有輸出的時(shí)候,就會(huì)現(xiàn)并發(fā)競(jìng)爭(zhēng),造成結(jié)果或輸出紊亂。這里就引入了鎖的概念,上面的代碼修改下,如下:

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

執(zhí)行的結(jié)果如下:

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

加鎖的結(jié)果會(huì)造成阻塞,而且會(huì)造成開鎖大。會(huì)根據(jù)順序由并發(fā)的多線程按順序輸出,如果后面的線程執(zhí)行過快,需要等待前面的進(jìn)程結(jié)束后其才能結(jié)束 --- 寫的貌似有點(diǎn)像隊(duì)列的概念了 ,不過在加鎖的很多場(chǎng)景下確實(shí)可以通過隊(duì)列去解決。

發(fā)表評(píng)論 共有條評(píng)論
用戶名: 密碼:
驗(yàn)證碼: 匿名發(fā)表
主站蜘蛛池模板: 呼和浩特市| 额尔古纳市| 沙湾县| 麟游县| 西城区| 沈丘县| 天等县| 苗栗市| 蒙城县| 平顶山市| 株洲市| 琼海市| 石城县| 称多县| 湾仔区| 岫岩| 池州市| 武隆县| 古蔺县| 方正县| 铜鼓县| 建水县| 湘潭县| 泸溪县| 忻城县| 冷水江市| 攀枝花市| 宜丰县| 苍南县| 青浦区| 招远市| 昌邑市| 财经| 新和县| 永新县| 石柱| 长葛市| 汪清县| 通海县| 宽甸| 徐水县|