前面已經(jīng)演示了Python:使用threading模塊實(shí)現(xiàn)多線(xiàn)程編程二兩種方式起線(xiàn)程和Python:使用threading模塊實(shí)現(xiàn)多線(xiàn)程編程三threading.Thread類(lèi)的重要函數(shù),這兩篇文章的示例都是演示了互不相干的獨(dú)立線(xiàn)程,現(xiàn)在我們考慮這樣一個(gè)問(wèn)題:假設(shè)各個(gè)線(xiàn)程需要訪(fǎng)問(wèn)同一公共資源,我們的代碼該怎么寫(xiě)?
'''
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()
解決上面的問(wèn)題,我們興許會(huì)寫(xiě)出這樣的代碼,我們假設(shè)跑200個(gè)線(xiàn)程,但是這200個(gè)線(xiàn)程都會(huì)去訪(fǎng)問(wèn)counter這個(gè)公共資源,并對(duì)該資源進(jìn)行處理(counter += 1),代碼看起來(lái)就是這個(gè)樣了,但是我們看下運(yùn)行結(jié)果:
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
打印結(jié)果我只貼了一部分,從中我們已經(jīng)看出了這個(gè)全局資源(counter)被搶占的情況,問(wèn)題產(chǎn)生的原因就是沒(méi)有控制多個(gè)線(xiàn)程對(duì)同一資源的訪(fǎng)問(wèn),對(duì)數(shù)據(jù)造成破壞,使得線(xiàn)程運(yùn)行的結(jié)果不可預(yù)期。這種現(xiàn)象稱(chēng)為“線(xiàn)程不安全”。在開(kāi)發(fā)過(guò)程中我們必須要避免這種情況,那怎么避免?這就用到了我們?cè)诰C述中提到的互斥鎖了。
互斥鎖概念
Python編程中,引入了對(duì)象互斥鎖的概念,來(lái)保證共享數(shù)據(jù)操作的完整性。每個(gè)對(duì)象都對(duì)應(yīng)于一個(gè)可稱(chēng)為” 互斥鎖” 的標(biāo)記,這個(gè)標(biāo)記用來(lái)保證在任一時(shí)刻,只能有一個(gè)線(xiàn)程訪(fǎng)問(wèn)該對(duì)象。在Python中我們使用threading模塊提供的Lock類(lèi)。
我們對(duì)上面的程序進(jìn)行整改,為此我們需要添加一個(gè)互斥鎖變量mutex = threading.Lock(),然后在爭(zhēng)奪資源的時(shí)候之前我們會(huì)先搶占這把鎖mutex.acquire(),對(duì)資源使用完成之后我們?cè)卺尫胚@把鎖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()
同步阻塞
當(dāng)一個(gè)線(xiàn)程調(diào)用Lock對(duì)象的acquire()方法獲得鎖時(shí),這把鎖就進(jìn)入“l(fā)ocked”狀態(tài)。因?yàn)槊看沃挥幸粋€(gè)線(xiàn)程1可以獲得鎖,所以如果此時(shí)另一個(gè)線(xiàn)程2試圖獲得這個(gè)鎖,該線(xiàn)程2就會(huì)變?yōu)椤癰lo同步阻塞狀態(tài)。直到擁有鎖的線(xiàn)程1調(diào)用鎖的release()方法釋放鎖之后,該鎖進(jìn)入“unlocked”狀態(tài)。線(xiàn)程調(diào)度程序從處于同步阻塞狀態(tài)的線(xiàn)程中選擇一個(gè)來(lái)獲得鎖,并使得該線(xiàn)程進(jìn)入運(yùn)行(running)狀態(tài)。
進(jìn)一步考慮
通過(guò)對(duì)公共資源使用互斥鎖,這樣就簡(jiǎn)單的到達(dá)了我們的目的,但是如果我們又遇到下面的情況:
遇到鎖嵌套的情況該怎么辦,這個(gè)嵌套是指當(dāng)我一個(gè)線(xiàn)程在獲取臨界資源時(shí),又需要再次獲取;
如果有多個(gè)公共資源,在線(xiàn)程間共享多個(gè)資源的時(shí)候,如果兩個(gè)線(xiàn)程分別占有一部分資源并且同時(shí)等待對(duì)方的資源;
上述這兩種情況會(huì)直接造成程序掛起,即死鎖,下面我們會(huì)談死鎖及可重入鎖RLock。
更多文章、技術(shù)交流、商務(wù)合作、聯(lián)系博主
微信掃碼或搜索:z360901061

微信掃一掃加我為好友
QQ號(hào)聯(lián)系: 360901061
您的支持是博主寫(xiě)作最大的動(dòng)力,如果您喜歡我的文章,感覺(jué)我的文章對(duì)您有幫助,請(qǐng)用微信掃描下面二維碼支持博主2元、5元、10元、20元等您想捐的金額吧,狠狠點(diǎn)擊下面給點(diǎn)支持吧,站長(zhǎng)非常感激您!手機(jī)微信長(zhǎng)按不能支付解決辦法:請(qǐng)將微信支付二維碼保存到相冊(cè),切換到微信,然后點(diǎn)擊微信右上角掃一掃功能,選擇支付二維碼完成支付。
【本文對(duì)您有幫助就好】元
