Python多線程編程(四):使用Lock互斥鎖

來源:互聯網
上載者:User
前面已經示範了Python:使用threading模組實現多線程編程二兩種方式起線程和Python:使用threading模組實現多線程編程三threading.Thread類的重要函數,這兩篇文章的樣本都是示範了互不相干的獨立線程,現在我們考慮這樣一個問題:假設各個線程需要訪問同一公用資源,我們的代碼該怎麼寫?

複製代碼 代碼如下:


'''
Created on 2012-9-8

@author: walfred
@module: thread.ThreadTest3
'''
import threading
import time

counter = 0

class MyThread(threading.Thread):
def __init__(self):
threading.Thread.__init__(self)

def run(self):
global counter
time.sleep(1);
counter += 1
print "I am %s, set counter:%s" % (self.name, counter)

if __name__ == "__main__":
for i in range(0, 200):
my_thread = MyThread()
my_thread.start()

解決上面的問題,我們興許會寫出這樣的代碼,我們假設跑200個線程,但是這200個線程都會去訪問counter這個公用資源,並對該資源進行處理(counter += 1),代碼看起來就是這個樣了,但是我們看下運行結果:
複製代碼 代碼如下:


I am Thread-69, set counter:64
I am Thread-73, set counter:66I am Thread-74, set counter:67I am Thread-75, set counter:68I am Thread-76, set counter:69I am Thread-78, set counter:70I am Thread-77, set counter:71I am Thread-58, set counter:72I am Thread-60, set counter:73I am Thread-62, set counter:74I am Thread-66,set counter:75I am Thread-70, set counter:76I am Thread-72, set counter:77I am Thread-79, set counter:78I am Thread-71, set counter:78


列印結果我只貼了一部分,從中我們已經看出了這個全域資源(counter)被搶佔的情況,問題產生的原因就是沒有控制多個線程對同一資源的訪問,對資料造成破壞,使得線程啟動並執行結果不可預期。這種現象稱為“線程不安全”。在開發過程中我們必須要避免這種情況,那怎麼避免?這就用到了我們在綜述中提到的互斥鎖了。

互斥鎖概念

Python編程中,引入了對象互斥鎖的概念,來保證共用資料操作的完整性。每個對象都對應於一個可稱為” 互斥鎖” 的標記,這個標記用來保證在任一時刻,只能有一個線程訪問該對象。在Python中我們使用threading模組提供的Lock類。

我們對上面的程式進行整改,為此我們需要添加一個互斥鎖變數mutex = threading.Lock(),然後在爭奪資源的時候之前我們會先搶佔這把鎖mutex.acquire(),對資源使用完成之後我們在釋放這把鎖mutex.release()。代碼如下:
複製代碼 代碼如下:


'''
Created on 2012-9-8

@author: walfred
@module: thread.ThreadTest4
'''

import threading
import time

counter = 0
mutex = threading.Lock()

class MyThread(threading.Thread):
def __init__(self):
threading.Thread.__init__(self)

def run(self):
global counter, mutex
time.sleep(1);
if mutex.acquire():
counter += 1
print "I am %s, set counter:%s" % (self.name, counter)
mutex.release()

if __name__ == "__main__":
for i in range(0, 100):
my_thread = MyThread()
my_thread.start()

同步阻塞

當一個線程調用Lock對象的acquire()方法獲得鎖時,這把鎖就進入“locked”狀態。因為每次只有一個線程1可以獲得鎖,所以如果此時另一個線程2試圖獲得這個鎖,該線程2就會變為“blo同步阻塞狀態。直到擁有鎖的線程1調用鎖的release()方法釋放鎖之後,該鎖進入“unlocked”狀態。線程發送器從處於同步阻塞狀態的線程中選擇一個來獲得鎖,並使得該線程進入運行(running)狀態。

進一步考慮

通過對公用資源使用互斥鎖,這樣就簡單的到達了我們的目的,但是如果我們又遇到下面的情況:

遇到鎖嵌套的情況該怎麼辦,這個嵌套是指當我一個線程在擷取臨界資源時,又需要再次擷取;
如果有多個公用資源,線上程間共用多個資源的時候,如果兩個線程分別佔有一部分資源並且同時等待對方的資源;

上述這兩種情況會直接造成程式掛起,即死結,下面我們會談死結及可重新進入鎖RLock。

  • 聯繫我們

    該頁面正文內容均來源於網絡整理,並不代表阿里雲官方的觀點,該頁面所提到的產品和服務也與阿里云無關,如果該頁面內容對您造成了困擾,歡迎寫郵件給我們,收到郵件我們將在5個工作日內處理。

    如果您發現本社區中有涉嫌抄襲的內容,歡迎發送郵件至: info-contact@alibabacloud.com 進行舉報並提供相關證據,工作人員會在 5 個工作天內聯絡您,一經查實,本站將立刻刪除涉嫌侵權內容。

    A Free Trial That Lets You Build Big!

    Start building with 50+ products and up to 12 months usage for Elastic Compute Service

    • Sales Support

      1 on 1 presale consultation

    • After-Sales Support

      24/7 Technical Support 6 Free Tickets per Quarter Faster Response

    • Alibaba Cloud offers highly flexible support services tailored to meet your exact needs.