




版權(quán)說明:本文檔由用戶提供并上傳,收益歸屬內(nèi)容提供方,若內(nèi)容存在侵權(quán),請進(jìn)行舉報或認(rèn)領(lǐng)
文檔簡介
第9章多任務(wù)編程課程描述多任務(wù)編程通常指用戶可以在同一時間內(nèi)運(yùn)行多個應(yīng)用程序,也指一個應(yīng)用程序內(nèi)可以在同一時間內(nèi)運(yùn)行多個任務(wù)。多任務(wù)編程是影響應(yīng)用程序性能的重要因素。本章知識點進(jìn)程的概念枚舉系統(tǒng)進(jìn)程threading模塊創(chuàng)建進(jìn)程終止進(jìn)程線程的概念9.1多進(jìn)程編程9.1.1什么是進(jìn)程9.1.2進(jìn)程的狀態(tài)9.1.1什么是進(jìn)程進(jìn)程是正在運(yùn)行的程序的實例。每個進(jìn)程至少包含一個線程,它從主程序開始執(zhí)行,直到退出程序,主線程結(jié)束,該進(jìn)程也被從內(nèi)存中卸載。主線程在運(yùn)行過程中還可以創(chuàng)建新的線程,實現(xiàn)多線程的功能。進(jìn)程由如下幾個部分組成。與程序相關(guān)聯(lián)的可執(zhí)行代碼的映像;內(nèi)存空間(通常是虛擬內(nèi)存中的一些區(qū)域),其中保存可執(zhí)行代碼、進(jìn)程的特定數(shù)據(jù)、用于記錄活動例程和其他事件的調(diào)用棧、用于保存實時產(chǎn)生的中間計算結(jié)果的堆(heap)。分配給進(jìn)程的資源的操作系統(tǒng)描述符(比如文件句柄)以及其他數(shù)據(jù)資源。安全屬性,比如進(jìn)程的所有者和權(quán)限。處理器的狀態(tài),比如寄存器的內(nèi)容、物理內(nèi)存地址等。9.1.2進(jìn)程的狀態(tài)
在操作系統(tǒng)內(nèi)核中,進(jìn)程可以被標(biāo)記成“被創(chuàng)建”(created)、“就緒”(ready)、“運(yùn)行”(running)、“阻塞”(blocked)、“掛起”(suspend)和“終止”(terminated)等狀態(tài)。各種狀態(tài)的切換過程如下:當(dāng)其被從存儲介質(zhì)中加載到內(nèi)存中,進(jìn)程的狀態(tài)為“被創(chuàng)建”。被創(chuàng)建后,進(jìn)程調(diào)度器會自動將進(jìn)程的狀態(tài)設(shè)置為“就緒”。此時,進(jìn)程等待調(diào)度器做上下文切換。處理器空閑時,器將進(jìn)程加載到處理器中,然后進(jìn)程的狀態(tài)變成“運(yùn)行”,處理器開始執(zhí)行該進(jìn)程的指令。如果進(jìn)程需要等待某個資源(比如用戶輸入、打開文件、執(zhí)行打印操作等),它將會被標(biāo)記為“阻塞”狀態(tài)。當(dāng)進(jìn)程獲得了等待的資源后,它的狀態(tài)又會變回“就緒”。當(dāng)內(nèi)存中的所有進(jìn)程都處于“阻塞”狀態(tài)時,Windows會將其中一個進(jìn)程設(shè)置為“掛起”狀態(tài),并將其在內(nèi)存中的數(shù)據(jù)保存到磁盤中。這樣可以釋放內(nèi)存空間給其他進(jìn)程。Windows也會把導(dǎo)致系統(tǒng)不穩(wěn)定的進(jìn)程掛起。一旦進(jìn)程執(zhí)行完成或者被操作系統(tǒng)終止,它就會被從內(nèi)存中移除或者被設(shè)置為“被終止”狀態(tài)。Windows進(jìn)程的狀態(tài)切換9.2進(jìn)程編程9.2.1創(chuàng)建進(jìn)程9.2.2枚舉系統(tǒng)進(jìn)程9.2.1創(chuàng)建進(jìn)程可以引用subprocess模塊來管理進(jìn)程,方法如下:importsubprocess1.subprocess.call()函數(shù)可以調(diào)用subprocess.call()方法創(chuàng)建進(jìn)程,基本語法如下:trtcode=subprocess.call(可執(zhí)行程序)trtcode返回可執(zhí)行程序的退出信息?!纠?-1】importsubprocessretcode=subprocess.call("notepad.exe")print(retcode)可以通過元祖的形式指定運(yùn)行程序的參數(shù),方法如下:trtcode=subprocess.call([可執(zhí)行程序,參數(shù)])【例9-2】importsubprocessretcode=subprocess.call(["notepad.exe","1.txt"])print(retcode)2.subprocess.Popen()函數(shù)進(jìn)程對象=subprocess.Popen(args,bufsize=0,executable=None,stdin=None,stdout=None,stderr=None,preexec_fn=None,close_fds=False,shell=False,cwd=None,env=None,universal_newlines=False,startupinfo=None,creationflags=0)參數(shù)說明如下
args:可以是字符串或者序列類型(例如列表和元組),用于指定進(jìn)程的可執(zhí)行文件及其參數(shù)。
bufsize:指定緩沖區(qū)的大小。
executable:用于指定可執(zhí)行程序。一般通過args參數(shù)來設(shè)置所要運(yùn)行的程序。如果將參數(shù)shell設(shè)為True,則executable用于指定程序使用的shell。在windows平臺下,默認(rèn)的shell由COMSPEC環(huán)境變量來指定,即命令窗口。
stdin:指定程序的標(biāo)準(zhǔn)輸入,默認(rèn)是鍵盤。
stdout:指定程序的標(biāo)準(zhǔn)輸出,默認(rèn)是屏幕。
stderr:指定程序的標(biāo)準(zhǔn)錯誤輸出,默認(rèn)是屏幕。
preexec_fn:只在Unix平臺下有效,用于指定一個可執(zhí)行對象,它將在子進(jìn)程運(yùn)行之前被調(diào)用。
close_fds:在windows平臺下,如果close_fds被設(shè)置為True,則新創(chuàng)建的子進(jìn)程將不會繼承父進(jìn)程的輸入、輸出和錯誤管道。
shell:如果shell被設(shè)為true,程序?qū)⑼ㄟ^shell來執(zhí)行。
cwd:指定進(jìn)程的當(dāng)前目錄。
env:指定進(jìn)程的環(huán)境變量。
universal_newlines:指定是否使用統(tǒng)一的文本換行符。在不同操作系統(tǒng)下,文本的換行符是不一樣的。例如,在windows下用'/r/n'表示換行,而Linux下用'/n'。如果將此參數(shù)設(shè)置為True,Python統(tǒng)一把這些換行符當(dāng)作'/n'來處理。
startupinfo和creationflags:只在windows下用效,它們將被傳遞給底層的CreateProcess()函數(shù),用于設(shè)置進(jìn)程的一些屬性,例如主窗口的外觀和進(jìn)程的優(yōu)先級等?!纠?-3】importsubprocessp=subprocess.Popen("dir",shell=True)p.wait()運(yùn)行結(jié)果python例9-3.py【例9-4】importsubprocessimportdatetimeprint(datetime.datetime.now())p=subprocess.Popen("pinglocalhost>nul",shell=True)print("程序執(zhí)行中...")p.wait()print(datetime.datetime.now())pinglocalhost>nul命令用于ping本機(jī),目的在于拖延時間,運(yùn)行結(jié)果如下:2014-12-0920:48:12.120471程序執(zhí)行中...2014-12-0920:48:15.2428603.CreateProcess函數(shù)CreateProcess(appName,commandLine,processAttributes,threadAttributes,bInheritHandles,dwCreationFlags,newEnvironment,currentDirectory,startupinfo參數(shù)說明如下:appName,要執(zhí)行的應(yīng)用程序名,可以包括結(jié)對路徑和文件名,通??梢詾镹ULL。commandLine,要執(zhí)行的命令行。processAttributes,新進(jìn)程的安全屬性,如果為None,則為默認(rèn)的安全屬性。ThreadAttributes,線程安全屬性,如果為None,則為默認(rèn)的安全屬性。bInheritHandles,繼承屬性,如果為None,則為默認(rèn)的繼承屬性。dwCreationFlags,指定附加的、用來控制優(yōu)先類和進(jìn)程創(chuàng)建的標(biāo)志。其取值見表9-1。這些屬性值都在win32process模塊中定義,例如,使用win32process.CREATE_NO_WINDOW可以指定新建進(jìn)程是一個沒有窗口的控制臺應(yīng)用程序。newEnvironment,指向新進(jìn)程的環(huán)境塊。如果為NULL,則使用調(diào)用CreateProcess()函數(shù)的進(jìn)程的環(huán)境。currentDirectory,進(jìn)程的當(dāng)前目錄。dwCreationFlags參數(shù)的取值取
值說
明CREATE_BREAKAWAY_FROM_JOB如果進(jìn)程與一個作業(yè)相關(guān)聯(lián),則其子進(jìn)程與該作業(yè)無關(guān)CREATE_DEFAULT_ERROR_MODE新進(jìn)程不繼承調(diào)用CreateProcess()函數(shù)的進(jìn)程的錯誤模式,而是使用缺省的錯誤模式CREATE_FORCE_DOS以MS-DOS模式運(yùn)行應(yīng)用程序CREATE_NEW_CONSOLE新進(jìn)程打開一個新的控制臺窗口,而不是使用調(diào)用進(jìn)程的控制臺窗口CREATE_NEW_PROCESS_GROUP新進(jìn)程是一個新進(jìn)程組的根進(jìn)程。新進(jìn)程組中包含新建進(jìn)程的所有后代進(jìn)程CREATE_NO_WINDOW新建進(jìn)程是一個沒有窗口的控制臺應(yīng)用程序,因此,它的控制臺句柄沒有被設(shè)置CREATE_SEPARATE_WOW_VDM只用于16位Windows應(yīng)用程序。如果設(shè)置,則新進(jìn)程在一個私有虛擬DOS機(jī)(VDM,VirtualDOSMachine)中運(yùn)行HIGH_PRIORITY_CLASS指定新建高優(yōu)先級的進(jìn)程IDLE_PRIORITY_CLASS指定只有系統(tǒng)空閑時才運(yùn)行新建級的進(jìn)程N(yùn)ORMAL_PRIORITY_CLASS創(chuàng)建一個普通進(jìn)程REALTIME_PRIORITY_CLASS指定新建最高優(yōu)先級的進(jìn)程CREATE_SHARED_WOW_VDM只用于16位Windows應(yīng)用程序。如果設(shè)置,則新進(jìn)程在一個共享虛擬DOS機(jī)中運(yùn)行CREATE_SUSPENDED創(chuàng)建一個處于掛起狀態(tài)的進(jìn)程CREATE_UNICODE_ENVIRONMENT如果設(shè)置了此選項,則參數(shù)newEnvironment使用Unicode字符串DEBUG_PROCESS啟動并調(diào)試新進(jìn)程及所有其創(chuàng)建的子進(jìn)程DEBUG_ONLY_THIS_PROCESS啟動并調(diào)試新進(jìn)程??梢哉{(diào)用WaitForDebugEvent()函數(shù)接收調(diào)試事件DETACHED_PROCESS對于控制臺程序,新進(jìn)程不繼承父控制臺ABOVE_NORMAL_PRIORITY_CLASS指定新建進(jìn)程的優(yōu)先級比NORMAL_PRIORITY_CLASS高,但是比HIGH_PRIORITY_CLASS低BELOW_NORMAL_PRIORITY_CLASS指定新建進(jìn)程的優(yōu)先級比IDLE_PRIORITY_CLASS高,但是比NORMAL_PRIORITY_CLASS低【例9-5】importwin32process#打開記事本程序,獲得其句柄handle=win32process.CreateProcess('C:\Windows\\notepad.exe','',None,None,0,win32process.CREATE_NO_WINDOW,None,None,win32process.STARTUPINFO())提示運(yùn)行本實例之前,需要下載和安裝Pywin32擴(kuò)展庫。9.2.2枚舉系統(tǒng)進(jìn)程1.CreateToolhelp32Snapshot()函數(shù)調(diào)用WindowsAPICreateToolhelp32Snapshot()可以獲取當(dāng)前系統(tǒng)運(yùn)行進(jìn)程的快照(snapshot),也就是運(yùn)行進(jìn)程的列表,其中包含進(jìn)程標(biāo)示符及其對應(yīng)的可執(zhí)行文件等信息,函數(shù)原型如下:HANDLEWINAPICreateToolhelp32Snapshot(DWORDdwFlags, //指定快照中包含的對象
DWORDth32ProcessID //指定獲取進(jìn)程快照的PID。如果為0,則獲取當(dāng)前系統(tǒng)進(jìn)程列表);參數(shù)dwFlags的取值取
值說
明TH32CS_SNAPALL(15,0x0000000F)相當(dāng)于指定了TH32CS_SNAPHEAPLIST,TH32CS_SNAPMODULE,TH32CS_SNAPPROCESS,和TH32CS_SNAPTHREADTH32CS_SNAPHEAPLIST(1,0x00000001)快照中包含指定進(jìn)程的堆列表TH32CS_SNAPMODULE(8,0x00000008)快照中包含指定進(jìn)程的模塊列表TH32CS_SNAPPROCESS(2,0x00000002)快照中包含進(jìn)程列表TH32CS_SNAPTHREAD(4,0x00000004)快照中包含線程列表調(diào)用CreateToolhelp32Snapshot()函數(shù)fromctypes.wintypesimport*fromctypesimport*調(diào)用CreateToolhelp32Snapshot()函數(shù)的代碼如下:kernel32=windll.kernel32hSnapshot=kernel32.CreateToolhelp32Snapshot(15,0))2.Process32First()函數(shù)BOOLWINAPIProcess32First(HANDLEhSnapshot, //之前調(diào)用CreateToolhelp32Snapshot()函數(shù)得到的進(jìn)程快照句柄
LPPROCESSENTRY32lppe //包含進(jìn)程信息的結(jié)構(gòu)體);如果函數(shù)執(zhí)行成功,則返回TRUE;否則返回FALSE。結(jié)構(gòu)體LPPROCESSENTRY32的定義如下typedefstructtagPROCESSENTRY32{DWORDdwSize; //結(jié)構(gòu)體的長度,單位是字節(jié)
DWORDcntUsage; //引用進(jìn)程的數(shù)量,必須為1DWORDth32ProcessID; //進(jìn)程標(biāo)示符(PID)
DWORDth32DefaultHeapID; //進(jìn)程的缺省堆標(biāo)識符
DWORDth32ModuleID; //進(jìn)程的模塊標(biāo)識符
DWORDcntThreads; //進(jìn)程中運(yùn)行的線程數(shù)量
DWORDth32ParentProcessID; //創(chuàng)建進(jìn)程的父進(jìn)程的標(biāo)識符
LONGpcPriClassBase; //進(jìn)程創(chuàng)建的線程的優(yōu)先級
DWORDdwFlags; //未使用
TCHARszExeFile[MAX_PATH]; //進(jìn)程對應(yīng)的可執(zhí)行文件名
DWORDth32MemoryBase; //可執(zhí)行文件的加載地址
DWORDth32AccessKey; //位數(shù)組,每一位指定進(jìn)程對地址的查看權(quán)限
}PROCESSENTRY32;結(jié)構(gòu)體tagPROCESSENTRY32classtagPROCESSENTRY32(Structure):_fields_=[('dwSize',DWORD),('cntUsage',DWORD),('th32ProcessID',DWORD),('th32DefaultHeapID',POINTER(ULONG)),('th32ModuleID',DWORD),('cntThreads',DWORD),('th32ParentProcessID',DWORD),('pcPriClassBase',LONG),('dwFlags',DWORD),('szExeFile',c_char*260)]在Python中調(diào)用Process32First()函數(shù)的代碼如下kernel32=windll.kernel32fProcessEntry32=tagPROCESSENTRY32()fProcessEntry32.dwSize=sizeof(fProcessEntry32)listloop=kernel32.Process32First(hSnapshot,byref(fProcessEntry32))3.Process32Next()函數(shù)BOOLWINAPIProcess32Next(HANDLEhSnapshot, //之前調(diào)用createtoolhelp32napshot()函數(shù)得到的進(jìn)程快照句柄
LPPROCESSENTRY32lppe//包含進(jìn)程信息的結(jié)構(gòu)體);如果函數(shù)執(zhí)行成功,則返回TRUE;否則返回FALSE。在Python中調(diào)用Process32Next()函數(shù)kernel32=windll.kernel32fProcessEntry32=tagPROCESSENTRY32()fProcessEntry32.dwSize=sizeof(fProcessEntry32)listloop=kernel32.Process32Next(hSnapshot,byref(fProcessEntry32))【例9-6】fromctypes.wintypesimport*fromctypesimport*kernel32=windll.kernel32#定義進(jìn)程信息結(jié)構(gòu)體classtagPROCESSENTRY32(Structure):_fields_=[('dwSize',DWORD),('cntUsage',DWORD),('th32ProcessID',DWORD),('th32DefaultHeapID',POINTER(ULONG)),('th32ModuleID',DWORD),('cntThreads',DWORD),('th32ParentProcessID',DWORD),('pcPriClassBase',LONG),('dwFlags',DWORD),('szExeFile',c_char*260)]#獲取當(dāng)前系統(tǒng)運(yùn)行進(jìn)程的快照hSnapshot=kernel32.CreateToolhelp32Snapshot(15,0)fProcessEntry32=tagPROCESSENTRY32()#初始化進(jìn)程信息結(jié)構(gòu)體的大小fProcessEntry32.dwSize=sizeof(fProcessEntry32)#獲取第一個進(jìn)程信息listloop=kernel32.Process32First(hSnapshot,byref(fProcessEntry32))whilelistloop:#如果獲取進(jìn)程信息成功,則繼續(xù)
processName=(fProcessEntry32.szExeFile)processID=fProcessEntry32.th32ProcessIDprint("%d:%s"%(processID,processName))#獲取下一個進(jìn)程信息
listloop=kernel32.Process32Next(hSnapshot,byref(fProcessEntry32))【例9-6】的運(yùn)行結(jié)果9.3多線程編程9.3.1線程的概念9.3.2threading模塊9.3.1線程的概念線程是操作系統(tǒng)可以調(diào)度的最小執(zhí)行單位,通常是將程序拆分成2個或多個并發(fā)運(yùn)行的任務(wù)。一個線程就是一段順序程序。但是線程不能獨立運(yùn)行,只能在程序中運(yùn)行。不同的操作系統(tǒng)實現(xiàn)進(jìn)程和線程的方法也不同,但大多數(shù)是在進(jìn)程中包含線程,Windows就是這樣。一個進(jìn)程中可以存在多個線程,線程可以共享進(jìn)程的資源(比如內(nèi)存)。而不同的進(jìn)程之間則是不能共享資源的。在操作系統(tǒng)內(nèi)核中,線程可以被標(biāo)記成如下狀態(tài)。初始化(Init):在創(chuàng)建線程,操作系統(tǒng)在內(nèi)部會將其標(biāo)識為初始化狀態(tài)。此狀態(tài)只在系統(tǒng)內(nèi)核中使用。就緒(Ready):線程已經(jīng)準(zhǔn)備好被執(zhí)行。延遲就緒(Deferredready):表示線程已經(jīng)被選擇在指定的處理器上運(yùn)行,但還沒有被調(diào)度。備用(Standby):、表示線程已經(jīng)被選擇下一個在指定的處理器上運(yùn)行。當(dāng)該處理器上運(yùn)行的線程因等待資源等原因被掛起時,調(diào)度器將備用線程切換到處理器上運(yùn)行。只有一個線程可以是備用狀態(tài)。運(yùn)行(Running):表示調(diào)度器將線程切換到處理器上運(yùn)行,它可以運(yùn)行一個線程周期(quantum),然后將處理器讓給其他線程。等待(Waiting):線程可以因為等待一個同步執(zhí)行的對象或等待資源等原因切換到等待狀態(tài)。關(guān)于線程同步將在8.3小節(jié)介紹。過渡(transition),表示線程已經(jīng)準(zhǔn)備好被執(zhí)行,但它的內(nèi)核堆已經(jīng)被從內(nèi)存中移除。一旦其內(nèi)核堆被加載到內(nèi)存中,線程就會變成運(yùn)行狀態(tài)。終止(Terminated):當(dāng)線程被執(zhí)行完成后,其狀態(tài)會變成終止。系統(tǒng)會釋放線程中的數(shù)據(jù)結(jié)構(gòu)和資源。Windows線程的狀態(tài)切換9.3.2threading模塊可以引用threading模塊來管理線程,導(dǎo)入threading模塊的方法如下:importthreading1.創(chuàng)建和運(yùn)行線程線程對象=threading.Thread(target=線程函數(shù),args=(參數(shù)列表),name=線程名,group=線程組)setDaemon()函數(shù)創(chuàng)建線程后,通常需要調(diào)用線程對象的setDaemon()方法將線程設(shè)置為守護(hù)線程。主線程執(zhí)行完后,如果還有其他非守護(hù)線程,則主線程不會退出,會被無限掛起;必須將線程聲明為守護(hù)線程之后,如果隊列中的線程運(yùn)行完了,那么整個程序不用等待就可以退出。setDaemon()函數(shù)的使用方法如下:線程對象.setDaemon(是否設(shè)置為守護(hù)線程)setDaemon()函數(shù)必須在運(yùn)行線程之前被調(diào)用。調(diào)用線程對象的start()方法可以運(yùn)行線程。【例9-7】線程編程的例子importthreadingdeff(i):print("Iamfromathread,num=%d\n"%(i))defmain():foriinrange(1,10):t=threading.Thread(target=f,args=(i,))t.setDaemon(True)t.start();
if__name__=="__main__":main();運(yùn)行結(jié)果Iamfromathread,num=1Iamfromathread,num=7Iamfromathread,num=8Iamfromathread,num=9Iamfromathread,num=2>>>Iamfromathread,num=3Iamfromathread,num=4Iamfromathread,num=5Iamfromathread,num=62.阻塞進(jìn)程調(diào)用線程對象的join()方法可以阻塞進(jìn)程直到線程執(zhí)行完畢。函數(shù)原型如下:join(timeout=None)參數(shù)timeout指定超時時間(單位為秒),超過指定時間join就不在阻塞進(jìn)程了?!纠?-8】importthreadingdeff(i):print("Iamfromathread,num=%d\n"%(i))defmain():foriinrange(1,10):t=threading.Thread(target=f,args=(i,))t.setDaemon(True)t.start();
t.join();if__name__=="__main__":main();程序的運(yùn)行結(jié)果如下:Iamfromathread,num=1Iamfromathread,num=7Iamfromathread,num=8Iamfromathread,num=9Iamfromathread,num=2Iamfromathread,num=3Iamfromathread,num=4Iamfromathread,num=5Iamfromathread,num=63.指令鎖當(dāng)多個線程同時訪問同一資源(比如全局變量),則可能會出現(xiàn)訪問沖突,【例9-9】當(dāng)多個線程同時訪問同一全局變量時出現(xiàn)訪問沖突的例子。importthreadingimporttimenum=0;deff():globalnumb=numtime.sleep(0.0001)num=b+1print('%s\n'%threading.currentThread().getName())defmain():foriinrange(1,20):t=threading.Thread(target=f)t.setDaemon(True)t.start();
t.join()print(num)if__name__=="__main__":main();程序的運(yùn)行結(jié)果如下:Thread-1Thread-2Thread-3
Thread-4
Thread-5Thread-6
Thread-7Thread-8Thread-9
Thread-10
Thread-11
Thread-12Thread-13
Thread-14Thread-15Thread-16
Thread-17
Thread-18Thread-19
13【例9-10】改進(jìn)【例9-9】,使用指令鎖避免多個線程同時訪問全局變量。importthreadingimporttimelock=threading.Lock()#創(chuàng)建一個指令鎖num=0;deff():globalnumiflock.acquire():print'%s獲得指令鎖.'%threading.currentThread().getName()b=numtime.sleep(0.0001)num=b+1lock.release()#釋放指令鎖
print'%s釋放指令鎖.'%threading.currentThread().getName()print('%s\n'%threading.currentThread().getName())defmain():foriinrange(1,20):t=threading.Thread(target=f)t.setDaemon(True)t.start();
t.join()print(num)if__name__=="__main__":main();程序的運(yùn)行結(jié)果如下:Thread-1獲得指令鎖.Thread-2獲得指令鎖.Thread-1釋放指令鎖.Thread-2釋放指令鎖.Thread-3獲得指令鎖.Thread-4獲得指令鎖.Thread-3釋放指令鎖.Thread-4釋放指令鎖.Thread-5獲得指令鎖.Thread-6獲得指令鎖.Thread-5釋放指令鎖.Thread-7獲得指令鎖.Thread-6釋放指令鎖.Thread-8獲得指令鎖.Thread-7釋放指令鎖.Thread-9獲得指令鎖.Thread-8釋放指令鎖.Thread-10獲得指令鎖.Thread-9釋放指令鎖.Thread-11獲得指令鎖.Thread-10釋放指令鎖.Thread-12獲得指令鎖.Thread-11釋放指令鎖.Thread-13獲得指令鎖.Thread-12釋放指令鎖.Thread-14獲得指令鎖.Thread-13釋放指令鎖.Thread-15獲得指令鎖.Thread-14釋放指令鎖.Thread-15釋放指令鎖.Thread-16獲得指令鎖.Thread-17獲得指令鎖.Thread-16釋放指令鎖.Thread-17釋放指令鎖.Thread-18獲得指令鎖.Thread-18釋放指令鎖.Thread-19獲得指令鎖.Thread-19釋放指令鎖.194.可重入鎖使用指令鎖可以避免多個線程同時訪問全局變量。但是如果一個線程里面有遞歸函數(shù),則它可能會多次請求訪問全局變量,此時,即使線程已經(jīng)獲得指令鎖,在它再次申請指令鎖時也會被阻塞。此時可以使用可重入鎖(RLock)。每個可重入鎖都關(guān)聯(lián)一個請求計數(shù)器和一個占有它的線程,當(dāng)請求計數(shù)器為0時,這個鎖可以被一個線程請求得到并把鎖的請求計數(shù)加1。如果同一個線程再次請求這個鎖時,請求計數(shù)器就會增加,當(dāng)該線程釋放RLock時,其計數(shù)器減1,當(dāng)計數(shù)器為0時,鎖被釋放??梢允褂胻hreading.RLock()方法創(chuàng)建一個個可重入鎖,例如:lock=threading.RLock()使用acquire()方法可以申請可重入鎖,使用release()方法可以釋放可重入鎖。具體用法與指令鎖相似。【例9-11】使用可重入鎖的例子。importthreadingimporttimelock=threading.RLock()#創(chuàng)建一個可重入鎖鎖num=0;deff():globalnum#第一次請求鎖定
iflock.acquire():print('%s獲得可重入鎖.\n'%(threading.currentThread().getName()))time.sleep(0.0001)#第2次請求鎖定
iflock.acquire():print('%s獲得可重入鎖.\n'%(threading.currentThread().getName()))time.sleep(0.0001)lock.release()#釋放指令鎖
print('%s釋放指令鎖.\n'%(threading.currentThread().getName()))time.sleep(0.0001)print('%s釋放指令鎖.\n'%(threading.currentThread().getName()))lock.release()#釋放指令鎖defmain():foriinrange(1,20):t=threading.Thread(target=f)t.setDaemon(True)t.start();
t.join()print(num)if__name__=="__main__":main();5.信號量創(chuàng)建信號量對象的方法如下:信號量對象=threading.Semaphore(計數(shù)器初值)例如,使用下面的語句可以創(chuàng)建一個計數(shù)器初值為2的信號量對象s。s=threading.Semaphore(2)【例9-12
溫馨提示
- 1. 本站所有資源如無特殊說明,都需要本地電腦安裝OFFICE2007和PDF閱讀器。圖紙軟件為CAD,CAXA,PROE,UG,SolidWorks等.壓縮文件請下載最新的WinRAR軟件解壓。
- 2. 本站的文檔不包含任何第三方提供的附件圖紙等,如果需要附件,請聯(lián)系上傳者。文件的所有權(quán)益歸上傳用戶所有。
- 3. 本站RAR壓縮包中若帶圖紙,網(wǎng)頁內(nèi)容里面會有圖紙預(yù)覽,若沒有圖紙預(yù)覽就沒有圖紙。
- 4. 未經(jīng)權(quán)益所有人同意不得將文件中的內(nèi)容挪作商業(yè)或盈利用途。
- 5. 人人文庫網(wǎng)僅提供信息存儲空間,僅對用戶上傳內(nèi)容的表現(xiàn)方式做保護(hù)處理,對用戶上傳分享的文檔內(nèi)容本身不做任何修改或編輯,并不能對任何下載內(nèi)容負(fù)責(zé)。
- 6. 下載文件中如有侵權(quán)或不適當(dāng)內(nèi)容,請與我們聯(lián)系,我們立即糾正。
- 7. 本站不保證下載資源的準(zhǔn)確性、安全性和完整性, 同時也不承擔(dān)用戶因使用這些下載資源對自己和他人造成任何形式的傷害或損失。
最新文檔
- 倉儲設(shè)備租賃合同協(xié)議書
- 人工智能技術(shù)應(yīng)用研發(fā)合作協(xié)議
- 鋼筋焊接施工承包合同
- 工程承包合同單價合同
- 企業(yè)信息化戰(zhàn)略規(guī)劃與實施
- 工廠場地租賃合同
- 電子商務(wù)購銷合同
- 數(shù)據(jù)安全與信息保密服務(wù)協(xié)議
- 血液(第二課時)課件2024-2025學(xué)年北師大版生物七年級下冊
- 關(guān)于調(diào)整辦公環(huán)境的申請通知
- 部編版六年級下冊數(shù)學(xué)教學(xué)計劃(及進(jìn)度表)
- 會計學(xué)生學(xué)情分析總結(jié)
- 大學(xué)英語六級考試
- 新質(zhì)生產(chǎn)力:中國創(chuàng)新發(fā)展的著力點與內(nèi)在邏輯
- 中考數(shù)學(xué)第二輪復(fù)習(xí)教案
- (2024年)職業(yè)健康培訓(xùn)課件(PPT9)
- 心理健康與職業(yè)生涯(中等職業(yè))全套教學(xué)課件
- 黑龍江農(nóng)業(yè)經(jīng)濟(jì)職業(yè)學(xué)院單招《語文》考試復(fù)習(xí)題庫(含答案)
- 人工智能在物業(yè)管理中的應(yīng)用
- 基于BIM的軸流通風(fēng)機(jī)施工工藝優(yōu)化
- 在醫(yī)院新員工入職儀式上的講話
評論
0/150
提交評論