




版權(quán)說明:本文檔由用戶提供并上傳,收益歸屬內(nèi)容提供方,若內(nèi)容存在侵權(quán),請進(jìn)行舉報或認(rèn)領(lǐng)
文檔簡介
1、 線程(線程(Thread)是程序中一個控制的)是程序中一個控制的執(zhí)行流程,屬進(jìn)程的一個實(shí)體。執(zhí)行流程,屬進(jìn)程的一個實(shí)體。 多任務(wù)操作系統(tǒng)就是采用多進(jìn)程和多多任務(wù)操作系統(tǒng)就是采用多進(jìn)程和多線程機(jī)制,即在同一時間內(nèi)有多個進(jìn)程在線程機(jī)制,即在同一時間內(nèi)有多個進(jìn)程在運(yùn)行,一個進(jìn)程可以有若干個線程即為多運(yùn)行,一個進(jìn)程可以有若干個線程即為多線程。線程。 采用多線程技術(shù)的目的是提高程序運(yùn)采用多線程技術(shù)的目的是提高程序運(yùn)行速度和行速度和CPU資源利用率。資源利用率。 本章主要討論本章主要討論MFC的多線程程序設(shè)計的多線程程序設(shè)計方法。方法。多線程基礎(chǔ)多線程基礎(chǔ)14.1多線程編程多線程編程14.2線程的終止線
2、程的終止14.3線程的優(yōu)先級與管理線程的優(yōu)先級與管理14.4線程之間的通信線程之間的通信14.5線程的同步線程的同步14.614.1 多線程基礎(chǔ)多線程基礎(chǔ) 多線程技術(shù)是多任務(wù)并發(fā)程序設(shè)計的多線程技術(shù)是多任務(wù)并發(fā)程序設(shè)計的基礎(chǔ),是提高程序運(yùn)行速度和增強(qiáng)數(shù)據(jù)處基礎(chǔ),是提高程序運(yùn)行速度和增強(qiáng)數(shù)據(jù)處理能力的重要技術(shù)手段。理能力的重要技術(shù)手段。 實(shí)際中,常常采用多線程編程技術(shù)提實(shí)際中,常常采用多線程編程技術(shù)提高應(yīng)用程序的性能。高應(yīng)用程序的性能。14.1.1 14.1.1 進(jìn)程與線程進(jìn)程與線程 進(jìn)程(進(jìn)程(Process)是程序在計算機(jī)內(nèi)存)是程序在計算機(jī)內(nèi)存中的運(yùn)行活動,是系統(tǒng)資源分配和調(diào)度的中的運(yùn)行活
3、動,是系統(tǒng)資源分配和調(diào)度的基本單位,是程序(基本單位,是程序(Program)即指令集)即指令集合和相關(guān)數(shù)據(jù)的動態(tài)體現(xiàn)。合和相關(guān)數(shù)據(jù)的動態(tài)體現(xiàn)。 進(jìn)程和程序的區(qū)別如下:進(jìn)程和程序的區(qū)別如下: (1)進(jìn)程描述的是程序的動態(tài)行為,)進(jìn)程描述的是程序的動態(tài)行為,而程序是一個指令序列和相關(guān)數(shù)據(jù)的靜態(tài)而程序是一個指令序列和相關(guān)數(shù)據(jù)的靜態(tài)描述;描述; (2)進(jìn)程是程序的一次運(yùn)行活動,具)進(jìn)程是程序的一次運(yùn)行活動,具有暫時性,而程序可以脫離機(jī)器長期保存,有暫時性,而程序可以脫離機(jī)器長期保存,具有永久性;具有永久性; (3)一個程序可以對應(yīng)多個進(jìn)程,一)一個程序可以對應(yīng)多個進(jìn)程,一個進(jìn)程也可以有多個程序,二者
4、沒有確定個進(jìn)程也可以有多個程序,二者沒有確定的對應(yīng)關(guān)系;的對應(yīng)關(guān)系; 進(jìn)程是為了刻畫程序內(nèi)部運(yùn)行狀態(tài)而進(jìn)程是為了刻畫程序內(nèi)部運(yùn)行狀態(tài)而引入的一個概念。引入的一個概念。 線程是由進(jìn)程創(chuàng)建的可執(zhí)行單元,線線程是由進(jìn)程創(chuàng)建的可執(zhí)行單元,線程依附于進(jìn)程的存在而共享進(jìn)程的內(nèi)存空程依附于進(jìn)程的存在而共享進(jìn)程的內(nèi)存空間,由應(yīng)用程序提供多個線程執(zhí)行控制。間,由應(yīng)用程序提供多個線程執(zhí)行控制。 線程也可以創(chuàng)建線程。線程和進(jìn)程一線程也可以創(chuàng)建線程。線程和進(jìn)程一樣具有一個生存周期,在這個生存周期中,樣具有一個生存周期,在這個生存周期中,總是處于某種狀態(tài)之中,諸如就緒態(tài)、運(yùn)總是處于某種狀態(tài)之中,諸如就緒態(tài)、運(yùn)行態(tài)或等待
5、(阻塞)態(tài)。行態(tài)或等待(阻塞)態(tài)。 當(dāng)進(jìn)程退出運(yùn)行以后,線程也隨之消當(dāng)進(jìn)程退出運(yùn)行以后,線程也隨之消失,所占用的資源也一同釋放。失,所占用的資源也一同釋放。 所以,在下列情況可以采用多線程編所以,在下列情況可以采用多線程編程技術(shù):程技術(shù): (1)為了提高運(yùn)行效率,在同一時間內(nèi))為了提高運(yùn)行效率,在同一時間內(nèi)運(yùn)行多個任務(wù)時;運(yùn)行多個任務(wù)時; (2)處理數(shù)據(jù)量比較大,需要等待時;)處理數(shù)據(jù)量比較大,需要等待時; (3)同一程序內(nèi)沒有順序關(guān)系的代碼段)同一程序內(nèi)沒有順序關(guān)系的代碼段時;時; (4)應(yīng)用系統(tǒng)采用客戶)應(yīng)用系統(tǒng)采用客戶/服務(wù)器機(jī)制時。服務(wù)器機(jī)制時。 程序設(shè)計使用多線程還要注意以下幾程序設(shè)
6、計使用多線程還要注意以下幾點(diǎn):點(diǎn): (1)多線程實(shí)際是多個程序段同時存)多線程實(shí)際是多個程序段同時存在并運(yùn)行于內(nèi)存中,不要讓太多的線程使在并運(yùn)行于內(nèi)存中,不要讓太多的線程使系統(tǒng)邏輯結(jié)構(gòu)變得復(fù)雜,線程并不是越多系統(tǒng)邏輯結(jié)構(gòu)變得復(fù)雜,線程并不是越多越好;越好; (2)有些情況下需要處理線程的同步)有些情況下需要處理線程的同步問題;問題; (3)搞清楚線程的優(yōu)先級設(shè)置和調(diào)度)搞清楚線程的優(yōu)先級設(shè)置和調(diào)度規(guī)則;規(guī)則; (4)搞清楚線程間的數(shù)據(jù)交換和通訊)搞清楚線程間的數(shù)據(jù)交換和通訊問題。問題。 14.1.2 14.1.2 線程分類線程分類 MFC將將Windows的線程處理功能封裝的線程處理功能封裝成
7、一個成一個CWinThread線程類,使程序設(shè)計更線程類,使程序設(shè)計更加方便簡捷。加方便簡捷。 MFC將將Windows線程分為兩類:一類線程分為兩類:一類是用于人機(jī)交互、處理用戶輸入的線程,是用于人機(jī)交互、處理用戶輸入的線程,稱為用戶界面線程(稱為用戶界面線程(User-Interface Threads);另一類是完成不需要用戶干);另一類是完成不需要用戶干預(yù)的或后臺執(zhí)行的操作,稱為工作者線程預(yù)的或后臺執(zhí)行的操作,稱為工作者線程或輔助線程(或輔助線程(Worker Threads)。)。 但對于但對于Windows API來說,由于它沒來說,由于它沒有引入類的概念,所以沒有用戶界面線程有引
8、入類的概念,所以沒有用戶界面線程和工作者線程之分,將二者等同處理,統(tǒng)和工作者線程之分,將二者等同處理,統(tǒng)稱為線程。稱為線程。14.2 多線程編程多線程編程 程序設(shè)計中采用多線程編程技術(shù),可程序設(shè)計中采用多線程編程技術(shù),可以有兩種途徑實(shí)現(xiàn)。以有兩種途徑實(shí)現(xiàn)。 一是采用一是采用Windows API提供的進(jìn)程創(chuàng)提供的進(jìn)程創(chuàng)建函數(shù)建函數(shù)CreateThread()進(jìn)行創(chuàng)建,用掛起、進(jìn)行創(chuàng)建,用掛起、恢復(fù)和終止、優(yōu)先級控制等函數(shù)實(shí)現(xiàn)線程恢復(fù)和終止、優(yōu)先級控制等函數(shù)實(shí)現(xiàn)線程管理;二是采用管理;二是采用MFC提供的提供的AfxBeginThread()函數(shù)創(chuàng)建,由函數(shù)創(chuàng)建,由CWinThread類進(jìn)行管理
9、。類進(jìn)行管理。 CWinThread封裝了封裝了Win32 API有關(guān)有關(guān)線程操作的函數(shù)。線程操作的函數(shù)。 本節(jié)在講述本節(jié)在講述Win32 API線程處理函數(shù)線程處理函數(shù)的基礎(chǔ)上,主要討論用的基礎(chǔ)上,主要討論用MFC提供的線程函提供的線程函數(shù)創(chuàng)建工作者線程和用戶界面線程的方法。數(shù)創(chuàng)建工作者線程和用戶界面線程的方法。 用戶界面線程和工作者線程的主要區(qū)用戶界面線程和工作者線程的主要區(qū)別是:前者需要響應(yīng)用戶輸入和處理系統(tǒng)別是:前者需要響應(yīng)用戶輸入和處理系統(tǒng)產(chǎn)生的事件與消息,擁有自己的消息隊列產(chǎn)生的事件與消息,擁有自己的消息隊列和消息循環(huán);而后者不需要處理這些消息和消息循環(huán);而后者不需要處理這些消息和
10、事件,沒有消息隊列和消息循環(huán)。和事件,沒有消息隊列和消息循環(huán)。14.2.1 Win32 API14.2.1 Win32 API線程處理線程處理 Windows API提供的線程操作函數(shù)有提供的線程操作函數(shù)有創(chuàng)建、掛起、恢復(fù)、終止以及優(yōu)先級控制創(chuàng)建、掛起、恢復(fù)、終止以及優(yōu)先級控制等。下面簡單介紹這幾個函數(shù)。等。下面簡單介紹這幾個函數(shù)。1 1線程創(chuàng)建線程創(chuàng)建 函數(shù)原型如下:函數(shù)原型如下: HANDLE CreateThread( LPSECURITY_ATTRIBUTES lpThreadAttributes, DWORD dwStackSize, LPTHREAD_START_ROUTINE l
11、pStartAddress, LPVOID lpParameter, DWORD dwCreationFlags, LPDWORD lpThreadId );2 2線程掛起線程掛起 函數(shù)原型如下:函數(shù)原型如下: DWORD SuspendThread( HANDLE hThread)3 3線程恢復(fù)線程恢復(fù) 函數(shù)原型如下:函數(shù)原型如下: DWORD ResumeThread(HANDLE hThread);14.2.2 14.2.2 工作者線程工作者線程 工作者線程是由工作者線程是由MFC提供的函數(shù)創(chuàng)建提供的函數(shù)創(chuàng)建的,它用于后臺處理一些費(fèi)時操作,如大的,它用于后臺處理一些費(fèi)時操作,如大數(shù)據(jù)量計
12、算、文件讀寫等操作,它沒有消數(shù)據(jù)量計算、文件讀寫等操作,它沒有消息循環(huán)。工作者線程的創(chuàng)建比較簡單,直息循環(huán)。工作者線程的創(chuàng)建比較簡單,直接調(diào)用接調(diào)用MFC的的AfxBeginThread()函數(shù)就可函數(shù)就可以。以。 該函數(shù)原型如下:該函數(shù)原型如下: CWinThread* AfxBeginThread( AFX_THREADPROC pfnThreadProc, LPVOID pParam, int nPriority = THREAD_PRIORITY_NORMAL, UINT nStackSize = 0, DWORD dwCreateFlags = 0, LPSECURITY_ATTRI
13、BUTES lpSecurityAttrs = NULL ); 【例例14-1】創(chuàng)建一個工作者線程。創(chuàng)建一個工作者線程。步驟如下:步驟如下: 圖圖14.1 工作者線程設(shè)計階段外觀工作者線程設(shè)計階段外觀 圖圖14.2 工作者線程運(yùn)行時界面工作者線程運(yùn)行時界面 14.2.3 14.2.3 用戶界面線程用戶界面線程 用戶界面線程就是響應(yīng)界面操作的線用戶界面線程就是響應(yīng)界面操作的線程,就像程,就像MFC中創(chuàng)建的對話框一樣。中創(chuàng)建的對話框一樣。 當(dāng)應(yīng)用程序需要處理用戶輸入并響應(yīng)當(dāng)應(yīng)用程序需要處理用戶輸入并響應(yīng)系統(tǒng)產(chǎn)生的事件和消息時,可以通過創(chuàng)建系統(tǒng)產(chǎn)生的事件和消息時,可以通過創(chuàng)建用戶界面線程實(shí)現(xiàn)。用戶界
14、面線程實(shí)現(xiàn)。 在在MFC中創(chuàng)建用戶界面線程比創(chuàng)建工中創(chuàng)建用戶界面線程比創(chuàng)建工作者線程稍麻煩些,仍然需要調(diào)用作者線程稍麻煩些,仍然需要調(diào)用MFC的的AfxBeginThread()函數(shù)的另一個版本。函數(shù)的另一個版本。 使用這個函數(shù)創(chuàng)建用戶界面線程時,使用這個函數(shù)創(chuàng)建用戶界面線程時,函數(shù)的入口參數(shù)與工作者線程有所區(qū)別。函數(shù)的入口參數(shù)與工作者線程有所區(qū)別。 該函數(shù)原型如下:該函數(shù)原型如下: CWinThread* AfxBeginThread( CRuntimeClass* pThreadClass, int nPriority = THREAD_PRIORITY_NORMAL, UINT nSta
15、ckSize = 0, DWORD dwCreateFlags = 0, LPSECURITY_ATTRIBUTES lpSecurityAttrs = NULL ); 【例例14-2】創(chuàng)建一個自己的用戶界創(chuàng)建一個自己的用戶界面線程,具體步驟如下:面線程,具體步驟如下: 圖圖14.3 用戶界面線程主窗口設(shè)計階段外觀用戶界面線程主窗口設(shè)計階段外觀 圖圖14.4 用戶界面線程外觀用戶界面線程外觀圖圖14.5 從從CWinThread派生用戶界面線程窗口外觀派生用戶界面線程窗口外觀 圖圖14.6 用戶界面線程演示主窗口用戶界面線程演示主窗口 圖圖14.7 用戶界面線程窗口用戶界面線程窗口14.3 線
16、程的終止線程的終止 一般情況下,線程執(zhí)行完成后就自動一般情況下,線程執(zhí)行完成后就自動結(jié)束即正常終止。結(jié)束即正常終止。 如果線程沒有執(zhí)行完預(yù)定任務(wù)或需要如果線程沒有執(zhí)行完預(yù)定任務(wù)或需要由外部某種事件強(qiáng)制結(jié)束稱為異常終止。由外部某種事件強(qiáng)制結(jié)束稱為異常終止。 線程除正常執(zhí)行完畢外,在調(diào)用了線程除正常執(zhí)行完畢外,在調(diào)用了ExitThread()函數(shù)、函數(shù)、ExitProcess()函數(shù)、函數(shù)、TerminateThread()函數(shù)和函數(shù)和TerminateProcess()函數(shù)后都可以終止線函數(shù)后都可以終止線程的運(yùn)行。程的運(yùn)行。 由由MFC創(chuàng)建的進(jìn)程也可以由這些函數(shù)創(chuàng)建的進(jìn)程也可以由這些函數(shù)終止運(yùn)行
17、。終止運(yùn)行。14.3.1 14.3.1 線程的正常終止線程的正常終止 通常,線程執(zhí)行到線程函數(shù)的結(jié)尾時,通常,線程執(zhí)行到線程函數(shù)的結(jié)尾時,系統(tǒng)會自動調(diào)用系統(tǒng)會自動調(diào)用Win32 API函數(shù)函數(shù)ExitThread()終止該線程,用戶不需要干預(yù)終止該線程,用戶不需要干預(yù)就可以結(jié)束一個線程,但如果某些條件需就可以結(jié)束一個線程,但如果某些條件需要線程退出運(yùn)行,就需要編程調(diào)用函數(shù)要線程退出運(yùn)行,就需要編程調(diào)用函數(shù)ExitThread()。 該函數(shù)原型如下:該函數(shù)原型如下: VOID ExitThread(DWORD dwExitCode) 14.3.2 14.3.2 線程的異常終止線程的異常終止 當(dāng)線
18、程沒有運(yùn)行結(jié)束時強(qiáng)行終止線程當(dāng)線程沒有運(yùn)行結(jié)束時強(qiáng)行終止線程的執(zhí)行稱為異常終止,異常終止需要調(diào)用的執(zhí)行稱為異常終止,異常終止需要調(diào)用Win32 API函數(shù)函數(shù)TerminateThread()終止線終止線程的運(yùn)行。程的運(yùn)行。 該函數(shù)原型如下:該函數(shù)原型如下:BOOL TerminateThread(HANDLE hThread,CDWORD dwExitCode)14.4 線程的優(yōu)先級與管理線程的優(yōu)先級與管理 在多任務(wù)操作系統(tǒng),如在多任務(wù)操作系統(tǒng),如Windows、UNIX中,將進(jìn)程和線程按其性質(zhì)分為不同中,將進(jìn)程和線程按其性質(zhì)分為不同類型,然后根據(jù)各自的類型,分別賦予不類型,然后根據(jù)各自的類
19、型,分別賦予不同的優(yōu)先級,方便系統(tǒng)的調(diào)度和控制。同的優(yōu)先級,方便系統(tǒng)的調(diào)度和控制。 14.4.1 14.4.1 線程的優(yōu)先級線程的優(yōu)先級 如前所述,同一進(jìn)程中的各個線程共如前所述,同一進(jìn)程中的各個線程共同分享進(jìn)程的同分享進(jìn)程的CPU資源。資源。 CPU時間的分配是由系統(tǒng)進(jìn)程(線程)時間的分配是由系統(tǒng)進(jìn)程(線程)調(diào)度程序控制的。調(diào)度程序控制的。 調(diào)度的一個基本原則是根據(jù)進(jìn)程的優(yōu)調(diào)度的一個基本原則是根據(jù)進(jìn)程的優(yōu)先級進(jìn)行時間片分配。先級進(jìn)行時間片分配。 線程也有自己的優(yōu)先級,線程的優(yōu)先線程也有自己的優(yōu)先級,線程的優(yōu)先級取決與兩個方面的因素:線程所在進(jìn)程級取決與兩個方面的因素:線程所在進(jìn)程的優(yōu)先級和線
20、程本身的優(yōu)先級。的優(yōu)先級和線程本身的優(yōu)先級。 也就是說,線程的實(shí)際優(yōu)先級是由上也就是說,線程的實(shí)際優(yōu)先級是由上述兩個優(yōu)先級組合成的優(yōu)先級,即基本優(yōu)述兩個優(yōu)先級組合成的優(yōu)先級,即基本優(yōu)先級確定的。先級確定的。 其中,進(jìn)程的優(yōu)先級分為其中,進(jìn)程的優(yōu)先級分為4個等級:個等級: (1)IDLE_PRIORITY_CLASS (2)NORMAL_ PRIORITY_CLASS (3)HIGH_PRIORITY_CLASS (4)REALTIME_ PRIORITY_CLASS 這這4個等級的優(yōu)先級順序依次增加,即個等級的優(yōu)先級順序依次增加,即REALTIME_ PRIORITY_CLASS的優(yōu)先級的優(yōu)先
21、級最高。最高。 線程的優(yōu)先級則是以進(jìn)程的優(yōu)先級為線程的優(yōu)先級則是以進(jìn)程的優(yōu)先級為基礎(chǔ),通過進(jìn)程的優(yōu)先級和線程的優(yōu)先級基礎(chǔ),通過進(jìn)程的優(yōu)先級和線程的優(yōu)先級計算出線程的基本優(yōu)先級。計算出線程的基本優(yōu)先級。 線程的優(yōu)先級分為線程的優(yōu)先級分為7個等級:個等級: (1)THREAD_PRIORITY_IDLE (2)THREAD_PRIORITY_LOWEST (3)THREAD_PRIORITY_BELOW_NORMAL (4)THREAD_PRIORITY_ NORMAL (5)THREAD_PRIORITY_ABOVE_NORMAL (6)THREAD_PRIORITY_HIGHEST (7)TH
22、READ_PRIORITY_TIME_CRITICAL 這這7個等級的優(yōu)先級依次提高,個等級的優(yōu)先級依次提高,THREAD_PRIORITY_TIME_CRITICAL的的優(yōu)先級最高。優(yōu)先級最高。 14.4.2 14.4.2 線程的優(yōu)先級管理線程的優(yōu)先級管理 從從14.2節(jié)創(chuàng)建線程的過程可以看出,節(jié)創(chuàng)建線程的過程可以看出,無論創(chuàng)建的是工作者線程還是用戶界面線無論創(chuàng)建的是工作者線程還是用戶界面線程,每個線程在創(chuàng)建時都有一個優(yōu)先級程,每個線程在創(chuàng)建時都有一個優(yōu)先級(實(shí)例采用默認(rèn)優(yōu)先級(實(shí)例采用默認(rèn)優(yōu)先級THREAD_PRIORITY_ NORMAL)。)。 線程創(chuàng)建后的優(yōu)先級可以根據(jù)實(shí)際情線程創(chuàng)建
23、后的優(yōu)先級可以根據(jù)實(shí)際情況改變。況改變。 MFC中中CWinThread類提供的方法就類提供的方法就可以設(shè)置和訪問線程的優(yōu)先級??梢栽O(shè)置和訪問線程的優(yōu)先級。1 1獲取線程的優(yōu)先級獲取線程的優(yōu)先級 CWinThread類獲取線程優(yōu)先級的函類獲取線程優(yōu)先級的函數(shù)原型如下:數(shù)原型如下: BOOL SetThreadPriority(int nPriority) 2 2設(shè)置線程的優(yōu)先級設(shè)置線程的優(yōu)先級 CWinThread類設(shè)置線程優(yōu)先級的函類設(shè)置線程優(yōu)先級的函數(shù)原型如下:數(shù)原型如下: int GetThreadPriority(void)14.4.3 14.4.3 線程的調(diào)度線程的調(diào)度 我們知道,線
24、程在一個生存周期中,我們知道,線程在一個生存周期中,總是處于就緒、運(yùn)行或阻塞狀態(tài)的某一個總是處于就緒、運(yùn)行或阻塞狀態(tài)的某一個狀態(tài)之中。狀態(tài)之中。 系統(tǒng)線程調(diào)度程序總是從線程就緒隊系統(tǒng)線程調(diào)度程序總是從線程就緒隊列中調(diào)度某個線程投入運(yùn)行。列中調(diào)度某個線程投入運(yùn)行。 如果就緒隊列中有多個線程的級別相如果就緒隊列中有多個線程的級別相同,系統(tǒng)就會為這些線程中的每個線程平同,系統(tǒng)就會為這些線程中的每個線程平均分配均分配CPU的時間;若這些線程中有級別的時間;若這些線程中有級別高的線程,系統(tǒng)就會分配高的線程,系統(tǒng)就會分配CPU時間片讓高時間片讓高級別的線程投入運(yùn)行,只有級別高的線程級別的線程投入運(yùn)行,只有
25、級別高的線程運(yùn)行完以后,低級別的線程才能獲得運(yùn)行完以后,低級別的線程才能獲得CPU的時間片投入運(yùn)行。的時間片投入運(yùn)行。 每一個線程運(yùn)行時要占用一個每一個線程運(yùn)行時要占用一個CPU,因此,單因此,單CPU的計算機(jī)系統(tǒng)只能有一個線的計算機(jī)系統(tǒng)只能有一個線程。程。 線程的優(yōu)先級在線程的優(yōu)先級在015的稱為普通優(yōu)先的稱為普通優(yōu)先級,是應(yīng)用程序中線程經(jīng)常使用的優(yōu)先級。級,是應(yīng)用程序中線程經(jīng)常使用的優(yōu)先級。 線程的優(yōu)先級在線程的優(yōu)先級在1531的統(tǒng)稱為實(shí)時的統(tǒng)稱為實(shí)時優(yōu)先級,它與普通優(yōu)先級的最大區(qū)別是相優(yōu)先級,它與普通優(yōu)先級的最大區(qū)別是相同優(yōu)先級的線程運(yùn)行不輪流占用同優(yōu)先級的線程運(yùn)行不輪流占用CPU時間時
26、間片,而是先運(yùn)行的線程先控制片,而是先運(yùn)行的線程先控制CPU,如果,如果它不主動放棄對它不主動放棄對CPU的控制,同級或低級的控制,同級或低級的線程就無法得到運(yùn)行。的線程就無法得到運(yùn)行。 為了使低級別的線程也能夠執(zhí)行,只為了使低級別的線程也能夠執(zhí)行,只能將高級別線程掛起。能將高級別線程掛起。 這是因?yàn)檫@是因?yàn)閃indows是一個強(qiáng)占式多任是一個強(qiáng)占式多任務(wù)的操作系統(tǒng),即任何時候系統(tǒng)都可以中務(wù)的操作系統(tǒng),即任何時候系統(tǒng)都可以中斷一個線程,強(qiáng)迫這個線程放棄斷一個線程,強(qiáng)迫這個線程放棄CPU的使的使用權(quán),并把用權(quán),并把CPU的使用權(quán)交給另一個線程。的使用權(quán)交給另一個線程。 在在Visual C+6.
27、0開發(fā)工具包中,提供開發(fā)工具包中,提供了一個用于觀察系統(tǒng)中運(yùn)行的進(jìn)程和線程了一個用于觀察系統(tǒng)中運(yùn)行的進(jìn)程和線程情況的實(shí)用工具情況的實(shí)用工具Process Viewer。 圖圖14.8 使用使用Process Viewer瀏覽瀏覽Exam14-2實(shí)例的線程實(shí)例的線程14.5 線程之間的通信線程之間的通信 我們知道,應(yīng)用程序中創(chuàng)建的工作線我們知道,應(yīng)用程序中創(chuàng)建的工作線程總是為主線程執(zhí)行某種特定的任務(wù)。程總是為主線程執(zhí)行某種特定的任務(wù)。 這樣,主線程和工作線程之間必須建這樣,主線程和工作線程之間必須建立一種信息傳遞機(jī)制,也就是線程間的通立一種信息傳遞機(jī)制,也就是線程間的通信。信。 線程間的通信方式
28、主要有全局變量方線程間的通信方式主要有全局變量方式和用戶自定義消息方式。式和用戶自定義消息方式。 下面討論這兩種方式是如何實(shí)現(xiàn)線程下面討論這兩種方式是如何實(shí)現(xiàn)線程間通信的。間通信的。14.5.1 14.5.1 通信機(jī)制通信機(jī)制 采用全局變量的方式進(jìn)行線程間通信采用全局變量的方式進(jìn)行線程間通信的機(jī)制非常簡單,因?yàn)槿肿兞吭趹?yīng)用程的機(jī)制非常簡單,因?yàn)槿肿兞吭趹?yīng)用程序中,任何一個對象都可以訪問它。序中,任何一個對象都可以訪問它。 線程隸屬于應(yīng)用程序的進(jìn)程,必然可線程隸屬于應(yīng)用程序的進(jìn)程,必然可以訪問系統(tǒng)的全局變量。以訪問系統(tǒng)的全局變量。 用戶自定義消息方式采用的是用戶自定義消息方式采用的是Wind
29、ows的消息驅(qū)動機(jī)制。的消息驅(qū)動機(jī)制。 工作者線程沒有消息循環(huán),不具備接工作者線程沒有消息循環(huán),不具備接收消息的條件,那么,主線程就不能以發(fā)收消息的條件,那么,主線程就不能以發(fā)送消息的方式與工作者線程進(jìn)行通信。送消息的方式與工作者線程進(jìn)行通信。 用戶界面線程是具有消息循環(huán)的,因用戶界面線程是具有消息循環(huán)的,因此,主線程和用戶界面線程能以發(fā)送消息此,主線程和用戶界面線程能以發(fā)送消息的方式進(jìn)行雙向通信。的方式進(jìn)行雙向通信。 不過,需要各自定義自己的消息處理不過,需要各自定義自己的消息處理函數(shù)。函數(shù)。 14.5.2 14.5.2 工作者線程通信工作者線程通信 【例例14-3】采用全局變量與工作者采用
30、全局變量與工作者線程通信,具體步驟如下:線程通信,具體步驟如下:圖圖14.9 工作者線程采用全局變量通信設(shè)計階段界面工作者線程采用全局變量通信設(shè)計階段界面 圖圖14.10 啟動線程后的界面啟動線程后的界面 圖圖14.11 停止線程后的界面停止線程后的界面14.5.3 14.5.3 用戶界面線程通信用戶界面線程通信 全局變量在線程通信中的應(yīng)用多是在全局變量在線程通信中的應(yīng)用多是在主線程對子線程的控制上,而從子線程向主線程對子線程的控制上,而從子線程向主線程的信息傳遞多采用自定義消息的方主線程的信息傳遞多采用自定義消息的方式進(jìn)行。式進(jìn)行。 由于用戶界面線程和主線程各自都有由于用戶界面線程和主線程各
31、自都有自己的消息循環(huán),所以二者之間可以采用自己的消息循環(huán),所以二者之間可以采用自定義消息方式相互通信。自定義消息方式相互通信。 【例例14-4】用戶界面線程中的自定用戶界面線程中的自定義消息方式通信。具體步驟如下:義消息方式通信。具體步驟如下: 圖圖14.12 自定義消息通信設(shè)計階段界面自定義消息通信設(shè)計階段界面 圖圖14.13 用戶界面線程對話框設(shè)計階段界面用戶界面線程對話框設(shè)計階段界面 圖圖14.14 自定義消息通信主界面自定義消息通信主界面 圖圖14.15 用戶界面線程運(yùn)行外觀用戶界面線程運(yùn)行外觀 圖圖14.16 用戶界面線程填充進(jìn)度條用戶界面線程填充進(jìn)度條 圖圖14.17 接收到用戶界
32、面線程的消息接收到用戶界面線程的消息14.6 線程的同步線程的同步 通常我們說的通常我們說的“同步同步”,是指同時做某,是指同時做某一件事情,即統(tǒng)一步伐。一件事情,即統(tǒng)一步伐。 線程的同步是指同一個進(jìn)程中的多個線程的同步是指同一個進(jìn)程中的多個線程能夠協(xié)調(diào)一致的工作。線程能夠協(xié)調(diào)一致的工作。 當(dāng)某種資源在任一時刻只允許一個線當(dāng)某種資源在任一時刻只允許一個線程訪問時,若另有線程也要訪問這個資源程訪問時,若另有線程也要訪問這個資源就會發(fā)生沖突;或當(dāng)某種資源在任一時刻就會發(fā)生沖突;或當(dāng)某種資源在任一時刻只允許只允許N個線程訪問,而多于個線程訪問,而多于N個線程訪問個線程訪問時就會發(fā)生沖突。時就會發(fā)生沖
33、突。 線程的同步就是為避免訪問系統(tǒng)資源線程的同步就是為避免訪問系統(tǒng)資源時發(fā)生沖突而提出來的。時發(fā)生沖突而提出來的。 所謂同步,實(shí)際上就是將可能要發(fā)生所謂同步,實(shí)際上就是將可能要發(fā)生沖突的線程阻塞,待不沖突時再將阻塞的沖突的線程阻塞,待不沖突時再將阻塞的線程投入運(yùn)行。線程投入運(yùn)行。 14.6.1 14.6.1 同步對象同步對象 MFC提供了提供了4種同步對象用于協(xié)調(diào)線種同步對象用于協(xié)調(diào)線程間的同步問題。程間的同步問題。 這這4種同步對象是事件對象種同步對象是事件對象CEvent、互持對象互持對象CMutex、信號量對象、信號量對象CSemaphore和臨界區(qū)對象和臨界區(qū)對象CCriticalSe
34、ction,他們的基類都是,他們的基類都是CSyncObject。 下面簡要介紹這下面簡要介紹這4個對象的構(gòu)造函數(shù)和個對象的構(gòu)造函數(shù)和基本用法?;居梅?。 1 1事件對象事件對象CEventCEvent CEvent對象的構(gòu)造函數(shù)原型如下:對象的構(gòu)造函數(shù)原型如下: CEvent(BOOL bInitiallyOwn = FALSE, BOOL bManualReset = FALSE, LPCTSTR lpszName = NULL, LPSECURITY_ATTRIBUTES lpsaAttribute = NULL ) 2 2信號量對象信號量對象CSemaphoreCSemaphore C
35、Semaphore對象的構(gòu)造函數(shù)如下:對象的構(gòu)造函數(shù)如下: CSemaphore( LONG lInitialCount = 1, LONG lMaxCount = 1, LPCTSTR pstrName = NULL, LPSECURITY_ATTRIBUTES lpsaAttributes = NULL ) 3 3臨界區(qū)對象臨界區(qū)對象CCriticalSectionCCriticalSection和互斥對象和互斥對象CMutexCMutex CCriticalSection對象的構(gòu)造函數(shù)原型對象的構(gòu)造函數(shù)原型比較簡單:比較簡單: CCriticalSection( ) CMutex對象的構(gòu)
36、造函數(shù)原型:對象的構(gòu)造函數(shù)原型: CMutex( BOOL bInitiallyOwn = FALSE, LPCTSTR lpszName = NULL, LPSECURITY_ATTRIBUTES lpsaAttribute = NULL );14.6.2 14.6.2 使用事件對象使用事件對象 使用事件對象是實(shí)現(xiàn)線程同步的最簡使用事件對象是實(shí)現(xiàn)線程同步的最簡單辦法。單辦法。 當(dāng)線程訪問某一資源前,需要等待某當(dāng)線程訪問某一資源前,需要等待某一事件發(fā)生時,可使用事件對象進(jìn)行同步。一事件發(fā)生時,可使用事件對象進(jìn)行同步。 例如,當(dāng)通信端口緩沖區(qū)接收到數(shù)據(jù)例如,當(dāng)通信端口緩沖區(qū)接收到數(shù)據(jù)時,訪問緩沖
37、區(qū)的線程才能被激活等。時,訪問緩沖區(qū)的線程才能被激活等。 下面用一個實(shí)例說明事件對象的使用下面用一個實(shí)例說明事件對象的使用方法。方法。 【例例14-5】使用事件同步對象,用使用事件同步對象,用兩個線程向編輯框?qū)憯?shù)據(jù),且一個線程訪兩個線程向編輯框?qū)憯?shù)據(jù),且一個線程訪問完成后再由另一個線程訪問。問完成后再由另一個線程訪問。 圖圖14.18 事件同步對象實(shí)例設(shè)計階段界面事件同步對象實(shí)例設(shè)計階段界面 圖圖14.19 未使用事件同步對象的輸出未使用事件同步對象的輸出 圖圖14.20 使用事件同步對象的輸出結(jié)果使用事件同步對象的輸出結(jié)果14.6.3 14.6.3 使用互斥對象使用互斥對象 系統(tǒng)中某些物理設(shè)
38、備或程序中的變量、系統(tǒng)中某些物理設(shè)備或程序中的變量、數(shù)據(jù)、表格、隊列等共享資源,不允許兩數(shù)據(jù)、表格、隊列等共享資源,不允許兩個線程同時使用,只能是一個線程用完了,個線程同時使用,只能是一個線程用完了,另一個線程才可以用,這種現(xiàn)象稱為互斥。另一個線程才可以用,這種現(xiàn)象稱為互斥。 保證互斥的基本模型是一個線程在使保證互斥的基本模型是一個線程在使用資源之前必須發(fā)出對這個資源的使用請用資源之前必須發(fā)出對這個資源的使用請求,稱為加鎖;在使用完之后釋放這個資求,稱為加鎖;在使用完之后釋放這個資源,稱為解鎖。源,稱為解鎖。 也就是說一個線程使用資源的順序是也就是說一個線程使用資源的順序是加鎖、使用和釋放。加
39、鎖、使用和釋放。 下面以實(shí)例說明互斥對象的使用方法。下面以實(shí)例說明互斥對象的使用方法。 【例例14-6】使用使用MFC的互斥同步對的互斥同步對象完成例象完成例14-5的任務(wù)。的任務(wù)。 圖圖14.21 使用互斥同步對象實(shí)例設(shè)計階段界面使用互斥同步對象實(shí)例設(shè)計階段界面 圖圖14.22 未使用互斥同步運(yùn)行效果未使用互斥同步運(yùn)行效果 圖圖14.23 使用互斥同步運(yùn)行效果使用互斥同步運(yùn)行效果14.6.4 14.6.4 使用臨界區(qū)對象使用臨界區(qū)對象 操作系統(tǒng)將一次僅能讓一個線程使用操作系統(tǒng)將一次僅能讓一個線程使用的資源稱為臨界資源,如一些輸入輸出的的資源稱為臨界資源,如一些輸入輸出的硬件設(shè)備和共享的數(shù)據(jù)資
40、源等都屬于臨界硬件設(shè)備和共享的數(shù)據(jù)資源等都屬于臨界資源。資源。 也就是說,臨界資源不允許兩個或兩也就是說,臨界資源不允許兩個或兩個以上的線程同時訪問。個以上的線程同時訪問。 MFC的臨界區(qū)同步對象和互斥同步對的臨界區(qū)同步對象和互斥同步對象很類似,也就是說使用臨界區(qū)對象時一象很類似,也就是說使用臨界區(qū)對象時一個線程只能擁有一個臨界區(qū)對象,而另一個線程只能擁有一個臨界區(qū)對象,而另一個線程使用臨界區(qū)對象只有等這個線程釋個線程使用臨界區(qū)對象只有等這個線程釋放了臨界區(qū)對象才可以使用。放了臨界區(qū)對象才可以使用。 14.6.5 14.6.5 使用信號量對象使用信號量對象 臨界區(qū)同步對象和互斥同步對象,對臨界
41、區(qū)同步對象和互斥同步對象,對共享資源的訪問在任一時刻只允許一個線共享資源的訪問在任一時刻只允許一個線程進(jìn)行,而信號量同步對象是限制同一資程進(jìn)行,而信號量同步對象是限制同一資源在這一刻訪問線程的數(shù)量。源在這一刻訪問線程的數(shù)量。 也就是說,某一資源可以允許同時有也就是說,某一資源可以允許同時有N個線程訪問,而第個線程訪問,而第N+1以后的線程只能掛起以后的線程只能掛起處于等待狀態(tài),當(dāng)處于等待狀態(tài),當(dāng)N個線程的某一個線程訪個線程的某一個線程訪問結(jié)束后,第問結(jié)束后,第N+1個線程立即投入運(yùn)行,這個線程立即投入運(yùn)行,這就是信號量同步對象的工作原理。就是信號量同步對象的工作原理。 【例例14-7】使用信號
42、量同步對象控使用信號量同步對象控制線程對資源的訪問數(shù)量。制線程對資源的訪問數(shù)量。 圖圖14.24 使用信號量同步對象實(shí)例外觀使用信號量同步對象實(shí)例外觀 圖圖14.25 信號量同步對象運(yùn)行界面圖信號量同步對象運(yùn)行界面圖 圖圖14.26 設(shè)定信號量同步和啟動線程數(shù)量設(shè)定信號量同步和啟動線程數(shù)量小結(jié)小結(jié) 本章在闡述進(jìn)程和線程的基礎(chǔ)上,以本章在闡述進(jìn)程和線程的基礎(chǔ)上,以具體的應(yīng)用實(shí)例,主要討論了具體的應(yīng)用實(shí)例,主要討論了MFC類庫對類庫對多線程程序設(shè)計的支持。多線程程序設(shè)計的支持。 概括起來有以下幾個方面:概括起來有以下幾個方面: (1)線程由創(chuàng)建到消失有一個生存周)線程由創(chuàng)建到消失有一個生存周期,分
43、為創(chuàng)建、掛起、運(yùn)行、終止,并且期,分為創(chuàng)建、掛起、運(yùn)行、終止,并且有相應(yīng)的函數(shù)支持這些操作。有相應(yīng)的函數(shù)支持這些操作。 由由MFC創(chuàng)建的線程可以使用創(chuàng)建的線程可以使用Win32 API函數(shù)終止、掛起或恢復(fù)運(yùn)行。函數(shù)終止、掛起或恢復(fù)運(yùn)行。 (2)MFC線程分為工作者線程和用戶線程分為工作者線程和用戶界面線程。界面線程。 工作者線程用于處理費(fèi)時或不需用戶工作者線程用于處理費(fèi)時或不需用戶干預(yù)的數(shù)據(jù)處理工作,而用戶界面線程主干預(yù)的數(shù)據(jù)處理工作,而用戶界面線程主要是為了響應(yīng)用戶輸入,處理系統(tǒng)發(fā)送的要是為了響應(yīng)用戶輸入,處理系統(tǒng)發(fā)送的消息和事件,后者具有消息隊列和消息循消息和事件,后者具有消息隊列和消息循
44、環(huán)。環(huán)。 (3)線程間的通信可采用全局變量和)線程間的通信可采用全局變量和自定義消息方式。自定義消息方式。 工作者線程和用戶界面線程都可以采工作者線程和用戶界面線程都可以采用全局變量和自定義消息方式進(jìn)行通信。用全局變量和自定義消息方式進(jìn)行通信。 工作者線程和用戶界面線程可以發(fā)送工作者線程和用戶界面線程可以發(fā)送消息到主線程,但工作者線程不能接收消消息到主線程,但工作者線程不能接收消息,因?yàn)楣ぷ髡呔€程沒有消息循環(huán)。息,因?yàn)楣ぷ髡呔€程沒有消息循環(huán)。 (4)線程的優(yōu)先級是由線程所在進(jìn)程)線程的優(yōu)先級是由線程所在進(jìn)程的優(yōu)先級和線程本身的優(yōu)先級確定的。的優(yōu)先級和線程本身的優(yōu)先級確定的。 進(jìn)程優(yōu)先級分為進(jìn)程
45、優(yōu)先級分為4個等級,線程的優(yōu)先個等級,線程的優(yōu)先級分為級分為7個等級,二者的組合構(gòu)成線程的基個等級,二者的組合構(gòu)成線程的基本優(yōu)先級,分為本優(yōu)先級,分為031共共32個等級,這個優(yōu)個等級,這個優(yōu)先級就是線程運(yùn)行時所具有的優(yōu)先級。先級就是線程運(yùn)行時所具有的優(yōu)先級。 線程的優(yōu)先級可以通過線程的優(yōu)先級可以通過Windows API或或CWinThread提供的函數(shù)進(jìn)行訪問。提供的函數(shù)進(jìn)行訪問。 (5) MFC提供了提供了4種同步對象,即事種同步對象,即事件對象件對象CEvent、互斥對象、互斥對象CMutex、臨界、臨界區(qū)對象區(qū)對象CCriticalsection和信號量對象和信號量對象CSemaph
46、ore,實(shí)現(xiàn)線程對象對訪問資源,實(shí)現(xiàn)線程對象對訪問資源的控制。的控制。 除信號量同步對象是控制同一時刻訪除信號量同步對象是控制同一時刻訪問資源的線程數(shù)量外,其他同步對象的目問資源的線程數(shù)量外,其他同步對象的目的是在同一時刻只能有一個線程對某種資的是在同一時刻只能有一個線程對某種資源進(jìn)行訪問。源進(jìn)行訪問。上機(jī)指導(dǎo)上機(jī)指導(dǎo) 實(shí)驗(yàn)一:工作者線程的設(shè)計和實(shí)現(xiàn)實(shí)驗(yàn)一:工作者線程的設(shè)計和實(shí)現(xiàn) 實(shí)驗(yàn)內(nèi)容實(shí)驗(yàn)內(nèi)容 工作者線程是多線程程序設(shè)計中使用工作者線程是多線程程序設(shè)計中使用最多的一種程序設(shè)計方法。最多的一種程序設(shè)計方法。 實(shí)際中如果多線程使用得當(dāng),可以大實(shí)際中如果多線程使用得當(dāng),可以大大提高程序的執(zhí)行效率
47、和性能。大提高程序的執(zhí)行效率和性能。 本例編寫一個工作者線程,并將主線本例編寫一個工作者線程,并將主線程中的參數(shù)傳遞給子線程。程中的參數(shù)傳遞給子線程。 實(shí)驗(yàn)?zāi)康膶?shí)驗(yàn)?zāi)康?掌握工作者線程函數(shù)的聲明格式和程掌握工作者線程函數(shù)的聲明格式和程序設(shè)計方法。序設(shè)計方法。 實(shí)現(xiàn)思路實(shí)現(xiàn)思路 仿照仿照14.2.2節(jié)的節(jié)的【例例14-1】,創(chuàng)建一個,創(chuàng)建一個基于基于MFC的工程,使用按鈕或菜單的單擊的工程,使用按鈕或菜單的單擊事件創(chuàng)建一個工作者線程,然后編寫線程事件創(chuàng)建一個工作者線程,然后編寫線程函數(shù)。函數(shù)。 注意這個函數(shù)是一個全局函數(shù)。注意這個函數(shù)是一個全局函數(shù)。 然后,編譯運(yùn)行程序,觀察線程函數(shù)然后,編譯運(yùn)
48、行程序,觀察線程函數(shù)是否啟動,是否按照自己的要求動作。是否啟動,是否按照自己的要求動作。 修改線程創(chuàng)建函數(shù)修改線程創(chuàng)建函數(shù)AfxBeginThread()入口參數(shù)入口參數(shù)LPVOID pParam的實(shí)際對象,在的實(shí)際對象,在線程函數(shù)中訪問這個指針,理解和體會這線程函數(shù)中訪問這個指針,理解和體會這個指針的作用。個指針的作用。 圖圖14.28是實(shí)驗(yàn)一設(shè)計階段參考界面,是實(shí)驗(yàn)一設(shè)計階段參考界面,圖圖14.29是運(yùn)行結(jié)果界面:是運(yùn)行結(jié)果界面: 圖圖14.28 實(shí)驗(yàn)一設(shè)計階段參考界面實(shí)驗(yàn)一設(shè)計階段參考界面 圖圖14.29 實(shí)驗(yàn)一運(yùn)行結(jié)果界面實(shí)驗(yàn)一運(yùn)行結(jié)果界面 下面是測試創(chuàng)建函數(shù)入口參數(shù)的代碼:下面是測試
49、創(chuàng)建函數(shù)入口參數(shù)的代碼: void CExperiment1Dlg:OnButton1() /AfxBeginThread(MyThread,this); CEdit *pEdit = (CEdit*)GetDlgItem(IDC_EDIT1); AfxBeginThread(MyThread,pEdit); UINT MyThread(LPVOID pParam) /CExperiment1Dlg *Dlg = (CExperiment1Dlg *)pParam; /CEdit *pEdit = (CEdit*)Dlg-GetDlgItem(IDC_EDIT1); CEdit *pEdit = (CEdit*)pParam; pEdit-SetWindowText(這是線程啟動后發(fā)的消息!); return 0; 實(shí)驗(yàn)二:線程同步對象使用實(shí)驗(yàn)二:線程同步對象使用 實(shí)驗(yàn)內(nèi)容實(shí)驗(yàn)內(nèi)容 線程同步是多線程程序設(shè)計中一個重線程同步是多線程程序設(shè)計中一個重要的問題。要的問題。 這里采用事件同步對象這里采用事件同步對象CEvent 實(shí)現(xiàn)線實(shí)現(xiàn)線程的同步。程的同步。 實(shí)驗(yàn)?zāi)康膶?shí)驗(yàn)?zāi)康?掌握同步對象掌握同步對
溫馨提示
- 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)用戶因使用這些下載資源對自己和他人造成任何形式的傷害或損失。
最新文檔
- 泥土人創(chuàng)意畫課件
- 安全文明教育培訓(xùn)
- 基藥政策培訓(xùn)
- 腫瘤的免疫逃逸機(jī)制研究
- 腫瘤患者便秘管理規(guī)范
- 關(guān)于員工思想培訓(xùn)課件
- 影視產(chǎn)業(yè)發(fā)展與市場機(jī)遇分析
- 教育信息化的發(fā)展與社會需求的關(guān)系研究
- 康復(fù)醫(yī)療市場現(xiàn)狀及未來展望
- 運(yùn)動健康運(yùn)動館
- 北京市2025學(xué)年高二(上)第一次普通高中學(xué)業(yè)水平合格性考試物理試題(解析版)
- 2025年四川省高考物理試卷真題(含答案)
- 數(shù)據(jù)庫應(yīng)用技術(shù)-第三次形考作業(yè)(第10章~第11章)-國開-參考資料
- 中建epc人防工程施工方案
- 湖南省長沙市雨花區(qū)2023-2024學(xué)年三年級下學(xué)期期末考試英語試題
- MOOC 新媒體文化十二講-暨南大學(xué) 中國大學(xué)慕課答案
- 2022年廣東省深圳市中考化學(xué)真題試卷
- 危險貨物道路運(yùn)輸安全生產(chǎn)管理制度
- GB∕T 8110-2020 熔化極氣體保護(hù)電弧焊用非合金鋼及細(xì)晶粒鋼實(shí)心焊絲
- 【完美排版】山東科技出版社二年級下冊綜合實(shí)踐活動教案
- 公共政策學(xué)(第三版)-課件
評論
0/150
提交評論