溫馨提示×

溫馨提示×

您好,登錄后才能下訂單哦!

密碼登錄×
登錄注冊×
其他方式登錄
點(diǎn)擊 登錄注冊 即表示同意《億速云用戶服務(wù)條款》

淺談Python線程的同步互斥與死鎖

發(fā)布時間:2020-08-27 03:15:26 來源:腳本之家 閱讀:133 作者:TeenJeen 欄目:開發(fā)技術(shù)

線程間通信方法

    1. 通信方法

線程間使用全局變量進(jìn)行通信

    2. 共享資源爭奪

共享資源:多個進(jìn)程或者線程都可以操作的資源稱為共享資源。對共享資源的操作代碼段稱為臨界區(qū)。

影響 : 對共享資源的無序操作可能會帶來數(shù)據(jù)的混亂,或者操作錯誤。此時往往需要同步互斥機(jī)制協(xié)調(diào)操作順序。

    3. 同步互斥機(jī)制

同步 : 同步是一種協(xié)作關(guān)系,為完成操作,多進(jìn)程或者線程間形成一種協(xié)調(diào),按照必要的步驟有序執(zhí)行操作。兩個或兩個以上的進(jìn)程或線程在運(yùn)行過程中協(xié)同步調(diào),按預(yù)定的先后次序運(yùn)行。比如 A 任務(wù)的運(yùn)行依賴于 B 任務(wù)產(chǎn)生的數(shù)據(jù)。

淺談Python線程的同步互斥與死鎖

互斥 : 互斥是一種制約關(guān)系,當(dāng)一個進(jìn)程或者線程占有資源時會進(jìn)行加鎖處理,此時其他進(jìn)程線程就無法操作該資源,直到解鎖后才能操作。一個公共資源同一時刻只能被一個進(jìn)程或線程使用,多個進(jìn)程或線程不能同時使用公共資源

淺談Python線程的同步互斥與死鎖

線程同步互斥方法

    線程Event同步

from threading import Event
e = Event() 創(chuàng)建線程event對象
e.wait([timeout]) 阻塞等待e被set
e.set() 設(shè)置e,使wait結(jié)束阻塞
e.clear() 使e回到未被設(shè)置狀態(tài)
e.is_set() 查看當(dāng)前e是否被設(shè)置

示例:

import time
import threading
 
event = threading.Event()
 
 
# 紅綠燈
def lighter():
  count = 0
  event.set() # 剛進(jìn)來的時候是綠燈
  while True:
    if 4 < count < 10:
      event.clear() # 清除設(shè)置,阻塞等待
      print("[信號燈]:紅,不能通行", count)
    elif count >= 10: # 添加設(shè)置,繼續(xù)執(zhí)行
      event.set()
      count = 0
    else:
      event.set() # 添加設(shè)置,繼續(xù)執(zhí)行
      print("[信號燈]:綠燈,可以通行", count)
    time.sleep(1)
    count += 1
 
 
# 汽車
def car(name):
  while True:
    if event.is_set():
      print("{0}: 綠燈 , 走起...".format(name))
      time.sleep(1)
    else:
      print("{0}: 紅燈 , 停車...".format(name))
      event.wait()
      print("{0}: 綠燈亮了 , 繼續(xù)前進(jìn)...".format(name))
 
 
light = threading.Thread(target=lighter, )
light.start()
car1 = threading.Thread(target=car, args=("小跑",))
car1.start()

    線程鎖 Lock

from threading import Lock
lock = Lock() #創(chuàng)建鎖對象
lock.acquire() #上鎖 如果lock已經(jīng)上鎖再調(diào)用會阻塞
lock.release() #解鎖

with lock: 上鎖

with代碼塊結(jié)束自動解鎖

示例:

from threading import Thread, Lock
from time import sleep
 
a = b = 0
lock = Lock()
 
 
# 子線程輸出a b
def value():
  while True:
    lock.acquire() # 上鎖
    if a != b:
      print("a = %d,b = %d" % (a, b))
    lock.release() # 解鎖
 
 
t = Thread(target=value)
t.start()
 
# 主線程加鎖更改a b時候,子線程處理a b 時也要進(jìn)行加鎖,重復(fù)加鎖就會阻塞等待主線程處理結(jié)束
# 同理主進(jìn)程再次更改a b 時等 子進(jìn)程結(jié)束才可以
while True:
  with lock: # 自動上/解鎖
    a += 1
    b += 1
t.join

死鎖及其處理

    1. 定義

        死鎖是指兩個或兩個以上的線程在執(zhí)行過程中,由于競爭資源或者由于彼此通信而造成的一種阻塞的現(xiàn)象,若無外力作用,它們都將無法推進(jìn)下去。此時稱系統(tǒng)處于死鎖狀態(tài)或系統(tǒng)產(chǎn)生了死鎖。

    2. 死鎖產(chǎn)生條件

        【互斥條件】:指線程對所分配到的資源進(jìn)行排它性使用,即在一段時間內(nèi)某資源只由一個進(jìn)程占用。如果此時還有其它進(jìn)程請求資源,則請求者只能等待,直至占有資源的進(jìn)程用畢釋放。

       【請求和保持條件】:指線程已經(jīng)保持至少一個資源,但又提出了新的資源請求,而該資源已被其它進(jìn)程占有,此時請求線程阻塞,但又對自己已獲得的其它資源保持不放。

        【不剝奪條件】:指線程已獲得的資源,在未使用完之前,不能被剝奪,只能在使用完時由自己釋放,通常CPU內(nèi)存資源是可以被系統(tǒng)強(qiáng)行調(diào)配剝奪的。

        【環(huán)路等待條件】:指在發(fā)生死鎖時,必然存在一個線程——資源的環(huán)形鏈,即進(jìn)程集合{T0,T1,T2,···,Tn}中的T0正在等待一個T1占用的資源;T1正在等待T2占用的資源,……,Tn正在等待已被T0占用的資源。

         簡單來說造成死鎖的原因可以概括成三句話:

【1】當(dāng)前線程擁有其他線程需要的資源

【2】當(dāng)前線程等待其他線程已擁有的資源

【3】都不放棄自己擁有的資源

淺談Python線程的同步互斥與死鎖

 T1擁有R1,T2擁有R2。T1請求使用R2,T2請求使用R1,但是T1,T2 都不愿釋放R1,R2,互相一直等待下去,造成死鎖

    3. 如何避免死鎖

        死鎖是我們非常不愿意看到的一種現(xiàn)象,我們要盡可能避免死鎖的情況發(fā)生。通過設(shè)置某些限制條件,去破壞產(chǎn)生死鎖的四個必要條件中的一個或者幾個,來預(yù)防發(fā)生死鎖。預(yù)防死鎖是一種較易實(shí)現(xiàn)的方法。但是由于所施加的限制條件往往太嚴(yán)格,可能會導(dǎo)致系統(tǒng)資源利用率。

from threading import Lock, Thread
 
 
# 交易類
class Account:
  def __init__(self, _id, balance, lock):
    self.id = _id
    self.balance = balance
    self.lock = lock # 各自賬戶鎖
 
  # 取錢
  def withdraw(self, amount):
    self.balance -= amount
 
  # 存錢
  def deposit(self, amount):
    self.balance += amount
 
  # 查看賬戶
  def get_balance(self):
    return self.balance
 
 
# 轉(zhuǎn)賬
def transfer(from_, to, amount):
  if from_.lock.acquire(): # 鎖住自己的賬戶
    from_.withdraw(amount) # 自己賬戶減少
    if to.lock.acquire(): # 鎖住對方賬戶
      to.deposit(amount) # 對方賬戶增加
      to.lock.release() # 解鎖對方賬戶
    from_.lock.release() # 自己賬戶解鎖
  print("轉(zhuǎn)賬完成")
 
 
Abby = Account("Abby", 5000, Lock())
Balen = Account("Balen", 3000, Lock())
 
t = Thread(target=transfer, args=(Abby, Balen, 1000))
t2 = Thread(target=transfer, args=(Balen, Abby, 500))
t.start()
t2.start()
t.join()
t2.join()
 
print("Abby:", Abby.get_balance())
print("Balen:", Balen.get_balance())

到此這篇關(guān)于淺談Python線程的同步互斥與死鎖的文章就介紹到這了,更多相關(guān)Python線程同步互斥與死鎖內(nèi)容請搜索億速云以前的文章或繼續(xù)瀏覽下面的相關(guān)文章希望大家以后多多支持億速云!

向AI問一下細(xì)節(jié)

免責(zé)聲明:本站發(fā)布的內(nèi)容(圖片、視頻和文字)以原創(chuàng)、轉(zhuǎn)載和分享為主,文章觀點(diǎn)不代表本網(wǎng)站立場,如果涉及侵權(quán)請聯(lián)系站長郵箱:is@yisu.com進(jìn)行舉報(bào),并提供相關(guān)證據(jù),一經(jīng)查實(shí),將立刻刪除涉嫌侵權(quán)內(nèi)容。

AI