版權(quán)說明:本文檔由用戶提供并上傳,收益歸屬內(nèi)容提供方,若內(nèi)容存在侵權(quán),請進行舉報或認(rèn)領(lǐng)
文檔簡介
1、第 10 章齊頭并進完成任務(wù)——多線程操作,多線程和多線程的實現(xiàn) 線程間數(shù)據(jù)同步 帶參數(shù)的線程線程池,第 10 章齊頭并進完成任務(wù)——多線程操作,多線程和多線程的實現(xiàn) 線程間數(shù)據(jù)同步 帶參數(shù)的線程線程池,10.1 多管齊下--多線程和多線程的實現(xiàn),多任務(wù)是在同一時間內(nèi)執(zhí)行多個任務(wù),在軟件開發(fā)的過程中,使用多線程技術(shù),可以提高程序的用戶滿意度,可以把占據(jù)長時間的程序中的任務(wù)放到后臺去處理,目前在桌面系統(tǒng)占主流的操作系統(tǒng)W
2、indows系列,就是多任務(wù)體系的典型代表,或者當(dāng)用戶點擊了一個按鈕去觸發(fā)按鈕的單擊事件,可以彈出一個進度條來顯示處理的進度,而不至使用戶誤會當(dāng)前任務(wù)的狀態(tài)。,10.1.1 線程的概念,在談?wù)摼€程之前,首先要了解進程。什么是進程呢?進程為應(yīng)用程序的運行實例,是應(yīng)用程序的一次動態(tài)執(zhí)行。,,一個進程是由多個線程所組成的,線程是程序執(zhí)行的基本原子單位,一個進程可以由多個線程組成。線程是“進程”中某個單一順序的控制流。線程是進程中的一個基本執(zhí)
3、行流,每個線程都有自己專屬的寄存器(程序計數(shù)器、棧指針等),代碼區(qū)共享,不同的線程可以執(zhí)行同樣的函數(shù)。,,我們現(xiàn)在可以坐在電腦旁邊,邊操作計算機使用媒體播放器播放mp3,邊使用PowerPoint,而這些任務(wù)之間絲毫不會相互干擾,這些都得益于多線程帶來的好處。多線程可以實現(xiàn)并行處理,避免了某項任務(wù)長時間占用CPU時間。要注意的是,多線程程序?qū)τ谛蕬?yīng)該根據(jù)任務(wù)不同的要求來選擇:如果兩個非常活躍的線程為了搶奪對CPU的控制權(quán),在線程
4、切換時會消耗的CPU資源,反而會降低系統(tǒng)的性能。,10.1.2 線程執(zhí)行函數(shù),在線程的相關(guān)知識中,Thread類是最重要的一個,所有起步的信息都包含在Thread類中。Thread類提供了創(chuàng)建并控制線程,設(shè)置其優(yōu)先級并獲取其狀態(tài)的方法。該類包含在System.Threading命名空間中。如果你想在你的應(yīng)用程序中使用多線程,就必須包含Thread類,而在使用Thread類之前,您的程序一定要使用如下語句,把System.Thread
5、ing命名空間包含進來: using System.Threading;,,Thread類中擁有4個重載的構(gòu)造函數(shù),使用最為廣泛的是:public Thread( ThreadStart start)參數(shù):start 參數(shù)類型:System.Threading ThreadStart ThreadStart委托,它表示此線程開始執(zhí)行時要調(diào)用的方法。 需要注意的是,ThreadStart是一個委托,在創(chuàng)
6、建線程時,在該線程上執(zhí)行的方法將通過一個傳遞給 Thread構(gòu)造函數(shù)的 ThreadStart 委托來表示。在調(diào)用 Start 方法之前,該線程不會開始執(zhí)行。,下面我們舉個例子來說明Thread的聲明。,01 //C#中的線程演示02 class ThreadSimple//定義類03 {04 //靜態(tài)線程函數(shù)05 public static void ThreadMethodExample(){06
7、}07 //調(diào)用靜態(tài)方法08 Thread ThreadSimple = new Thread (ThreadSimple .ThreadMethodExample)在這個實例中,創(chuàng)建了一個線程對象ThreadSimple,并且清楚的告訴了我們靜態(tài)線程函數(shù)的使用。在實際的代碼編寫時,還可以使用更簡單的線程定義方式:,,01 Thread ThreadSimple = new Thread(new ThreadSta
8、rt(ThreadMethodExample));很多人都認(rèn)為第一種方式有點復(fù)雜,而愿意采用第二種更簡單的方式定義線程,兩種方式的效果是完全一樣,第二種方式寫出的程序更簡潔。,10.1.3 啟動線程,現(xiàn)在我們有了一個線程,如何啟動這個線程呢?在Thread中提供了Start方法,通過調(diào)用該方法,可以啟動線程。Thread.Start方法啟動線程:即新建并啟動一個線程的代碼如下。ThreadSimple.Start();,
9、在Thread這個類以對象的方式提供一些必要的實例成員,其中下面這些是比較常用的:,⑴ IsAlive:判斷線程是否處于活動狀態(tài)。⑵ Name:線程的名稱。⑶ Priority:ThreadPriority枚舉類型,代表線程的優(yōu)先級。⑷ ThreadState:ThreadState枚舉類型,代表線程的狀態(tài)。⑸ Start:啟動一個線程。⑹ Suspend:掛起一個線程的運行。⑺ Resume:繼續(xù)掛起的線程。⑻ Abor
10、t:結(jié)束一個線程的運行。,當(dāng)線程創(chuàng)建完畢之后并啟動之后,控制線程的工作還有以下幾件事需要完成:,線程的優(yōu)先級:ThreadPriority屬性用于設(shè)置線程的級別。在枚舉類型ThreadPriorit中定義了以下成員,分別對應(yīng)一種線程級別。Normal:普通級別。AboveNormal:高于普通級別。BelowNormal:低于普通級別。Highest:最高級別。Lowest:最低級別。,,下面的語句把線程的級別設(shè)成了最高。
11、 ThreadSimple.priority = ThreadPriority.Highest;⑵ 線程的休眠:休眠線程是讓進程進入一定時間的休眠狀態(tài),時間一到,線程將繼續(xù)運行。這可以通過Thread的Sleep方法實現(xiàn)。Thread類中有兩個重載的Sleep方法,一個帶有int類型的參數(shù),指定休眠的毫秒數(shù),另一個帶有TimeSpan類型的參數(shù),指定休眠的時間段。,例如,下面兩個Sleep調(diào)用效果是相同的,都是休眠10秒鐘,0
12、1 Thread.Sleep(10000);02 Thread.Sleep(New TimeSpan(0, 0, 0, 0, 10000));⑸ 線程的掛起:和休眠不同,線程的掛起是暫停線程,如果不再啟動線程,它將永遠保持暫停狀態(tài)。只有當(dāng)前運行的線程才可以掛起,對已經(jīng)掛起的線程實施掛起操作沒有任何效果。代碼如下。01 //如果線程的狀態(tài)是運行02 if (NewThread.ThreadState = = T
13、hreadState.Running)03 {04 //線程掛起05 NewThread.Suspend();06 },,這里通過查詢Thread的ThreadState屬性檢查線程是否在運行。⑹ 線程的繼續(xù):掛起線程可以使用Thread.Resume方法繼續(xù)運行。對沒有掛起的線程使用繼續(xù)操作將沒有任何結(jié)果。代碼如下。01 //如果線程的狀態(tài)是掛起02 if (NewThread.ThreadSt
14、ate = ThreadState.Suspended)03 {04 //線程繼續(xù)05 NewThread.Resume();06 },【拓展訓(xùn)練】 在C#中輸出線程的名字,剛才,我們學(xué)習(xí)了線程中的實例成員,怎么用呢?我能否給線程命名,并且輸出線程的名字呢?這個是完全可以做到的,用上面給出的實例方法寫成如下代碼就可做到:,10.1.4 結(jié)束線程,在C#中,System.Threading命名空間提供一些使得可
15、以進行多線程編程的類和接口。除同步線程活動和數(shù)據(jù)訪問的類之外,此命名空間還包含一個 ThreadPool類,它使用戶能夠使用系統(tǒng)提供的線程池和一個 Timer類,在線程池線程上執(zhí)行回調(diào)方法。Thread類有幾個重要的方法,描述如下:Abort():調(diào)用此方法通常會終止線程。在調(diào)用此方法的線程上引發(fā) ThreadAbortException,以開始終止此線程的過程。Sleep(int):已重載。 將當(dāng)前線程阻塞指定的毫秒數(shù)。該方法是
16、靜態(tài)方法,,Suspend():該方法并不終止未完成的線程,它僅僅掛起線程,以后還可恢復(fù)。 Resume():恢復(fù)被Suspend()方法掛起的線程的執(zhí)行 。 現(xiàn)在我們動手編寫一個完整線程操作的例子,從創(chuàng)建線程,運行線程,終止線程的全程操作。,【范例10-1】 C#中的線程程序,在這段程序中為了對我們已經(jīng)學(xué)習(xí)到的知識進行擴展,程序中還有意的使用了Thread.ThreadState屬性,這個屬性代表了線程運行時狀態(tài),指示
17、當(dāng)前線程的狀態(tài)的枚舉值之一,ThreadState 為線程定義了一組所有可能的執(zhí)行狀態(tài)。一旦線程被創(chuàng)建,它就至少處于其中一個狀態(tài)中,直到終止。在公共語言運行時中創(chuàng)建的線程最初處于 Unstarted狀態(tài),而進入運行時的外部線程則已經(jīng)處于 Running 狀態(tài)。通過調(diào)用 Start 方法可以將 Unstarted 線程轉(zhuǎn)換為 Running 狀態(tài)。并非所有的 ThreadState 值的組合都是有效的;例如,線程不能同時處于 Aborte
18、d 和 Unstarted 狀態(tài)中。 ThreadState在各種情況下的可能取值如下:,,第 10 章齊頭并進完成任務(wù)——多線程操作,多線程和多線程的實現(xiàn) 線程間數(shù)據(jù)同步 帶參數(shù)的線程線程池,10.2 合理利用資源--線程間數(shù)據(jù)同步,通過上面的學(xué)習(xí),對于線程我們已經(jīng)有了一個簡單的印象,已經(jīng)可以簡單的操作一個線程了,但是在當(dāng)一個程序存在多個線程時,其間的線程間數(shù)據(jù)同步問題有隨之而來。我們在這個章節(jié)中,將探討如何解決這個問題。,
19、10.2.1 線程間數(shù)據(jù)共享,在多線程編程中,如果線程間需要共享數(shù)據(jù),需要的操作是把要共享的數(shù)據(jù)設(shè)置成靜態(tài)類型的,使用關(guān)鍵字static,比如,我們需要共享ShareDateInt這個整形變量,則在程序中按照下面的方法就可以: static int ShareDateInt = 0;上面的語句聲明一個靜態(tài)整形變量ShareDateInt。,然后我們創(chuàng)建多個線程: 01 ShareData ShareDdataC;//
20、聲明ShareData對象ShareDdataC02 Thread[] ThreadArray;//聲明線程數(shù)組03 ThreadArray = new Thread[5];//創(chuàng)建線程數(shù)組04 ShareDdataC = new ShareData();//構(gòu)造ShareDdataC對象05 for (int i = 0; i < 5; ++i)//使用循環(huán)的方式創(chuàng)建多個線程06
21、 {07 ThreadArray[i] = new Thread(new ThreadStart(ShareDdataC.ThreadFunc));08 ThreadArray[i].Start();//線程運行09 Thread.Sleep(500);//主線程睡眠10 },10.2.2 lock語句同步數(shù)據(jù)訪問,在編程中,我們會遇到同時需要對某個
22、數(shù)據(jù)進行操作的情況,如果我們在程序中需要處理這樣的情況,兩個線程需要同時操作一個隊列,一個線程進行添加操作,另外一個線程進行取用元素操作,這是一個典型的生產(chǎn)者和消費者問題,添加元素的線程為生產(chǎn)者,取用元素的線程為消費者。這個問題是多線程應(yīng)用中一個必須解決的問題,這個問題涉及到線程之間更深層次的操作:線程之間的同步和通訊處理。 這些操作我們以前往往不能很好的進行處理,自從C#語言中引入了lock這個關(guān)鍵字,以上問題就比較容易予以解決了。
23、 lock 關(guān)鍵字將語句塊標(biāo)記為臨界區(qū),方法是獲取給定對象的互斥鎖,執(zhí)行語句,然后釋放該鎖。此語句的形式如下:,Lock語句的語法規(guī)則:,lock(expression) statement_block其中,expression是加鎖對象,必須是引用類型,不能是數(shù)值類型;statement_block代表正在訪問共享資源的程序段。下面就是一段對lock使用的演示代碼: 【范例10-2】 創(chuàng)建程序,熟悉線程中的lock語句的用法
24、,10.2.3 Mutex類同步數(shù)據(jù)訪問,當(dāng)兩個或更多線程需要同時訪問一個共享資源時,系統(tǒng)需要使用同步機制來確保一次只有一個線程使用該資源。Mutex類就是.net給我們提供一個非常有幫助的類,它只向一個線程授予對共享資源的獨占訪問權(quán)。如果一個線程獲取了互斥體,則要獲取該互斥體的第二個線程將被掛起,直到第一個線程釋放該互斥體。在Mutex類中有三個關(guān)鍵的方法:,,可以使用 WaitHandle.WaitOne 方法請求互斥體的所屬權(quán)。
25、擁有互斥體的線程可以在對 WaitOne的重復(fù)調(diào)用中請求相同的互斥體而不會阻止其執(zhí)行。但線程必須調(diào)用 ReleaseMutex 方法同樣多的次數(shù)以釋放互斥體的所屬權(quán)。 線程使用Mutex.WaitOne()方法等待Mutex對象被釋放,如果它等待的Mutex對象被釋放了,它就自動擁有這個對象,直到它調(diào)用Mutex.ReleaseMutex()方法釋放這個對象,而在此期間,其他想要獲取這個Mutex對象的線程都只有等待。,,【范例10-
26、3】 演示Mutex類的使用,Mutex類的使用,也許需要事先聲明一個互斥體,我們使用一個簡單的程序演示Mutex類的使用。,10.2.4 Monitor類同步數(shù)據(jù)訪問數(shù),當(dāng)多線程公用一個對象時,也會出現(xiàn)和公用代碼類似的問題,這種問題就不應(yīng)該使用lock關(guān)鍵字了,這里需要用到System.Threading中的一個類Monitor,我們可以稱之為監(jiān)視器,Monitor提供了使線程共享資源的方案。C# Monitor類可以鎖定對象,
27、一個線程只有得到這把鎖才可以對該對象進行操作。對象鎖機制保證了在可能引起混亂的情況下一個時刻只有一個線程可以訪問這個對象。,,第 10 章齊頭并進完成任務(wù)——多線程操作,多線程和多線程的實現(xiàn) 線程間數(shù)據(jù)同步 帶參數(shù)的線程線程池,10.3 帶參數(shù)的線程,.Net讓我們很輕松就可以創(chuàng)建一個線程,但是它提供的創(chuàng)建線程和啟動線程的方法沒有明顯的提供參數(shù),假如我們要用線程來啟動類里面一個帶參數(shù)的方法該怎么辦?在多線程或單線程任務(wù)中,讓線
28、程帶傳入?yún)?shù)一直是個麻煩的問題,我們將介紹C#中帶參數(shù)線程處理方法。,10.3.1 帶參數(shù)線程處理函數(shù),在不傳遞參數(shù)情況下,使用ThreadStart代理來連接執(zhí)行函數(shù),如果希望傳遞參數(shù)給執(zhí)行函數(shù),則使用ParameterizedThreadStart代理來鏈接執(zhí)行函數(shù),使用Thread類提供給我們四個重載的構(gòu)造函數(shù):Thread (ThreadStart):初始化 Thread 類的新實例。 Thread (Parameteri
29、zedThreadStart):初始化 Thread 類的新實例,指定允許對象在線程啟動時傳遞給線程的委托。 Thread (ParameterizedThreadStart, Int32):初始化 Thread 類的新實例,指定允許對象在線程啟動時傳遞給線程的委托,并指定線程的最大堆棧大小。 Thread (ThreadStart, Int32):初始化 Thread 類的新實例,指定線程的最大堆棧大小。,10.3.2 使用
30、帶參數(shù)線程,在處理的時候,如果不帶參數(shù)的線程用ThreadStart,如果帶一個參數(shù)的時候我們用ParameterizedThreadStart。帶多個參數(shù)的用另外的方法。 下面我們看一下具體的情況:1. 不帶參數(shù)的情況下,使用下面的示例程序就可以完成一個最簡單線程程序:2. 帶一個參數(shù)的 由于ParameterizedThreadStart要求參數(shù)類型必須為object,所以定義的方法MethodsOne形參類型必須為objec
31、t。3. 帶多個參數(shù)的 由于Thread默認(rèn)只提供了這兩種構(gòu)造函數(shù),如果需要傳遞多個參數(shù),我們可以自己將參數(shù)作為類的屬性。定義類的對象時候?qū)嵗@個屬性,然后進行操作。,,4. 利用結(jié)構(gòu)體給參數(shù)傳值。 為多線程方法調(diào)用提供多個參數(shù)的最好辦法是將目標(biāo)方法包裹在結(jié)構(gòu)中,這種方法的優(yōu)點是,無論需要傳遞任何參數(shù),都可以在結(jié)構(gòu)內(nèi)方便的完成封裝和傳遞。,第 10 章齊頭并進完成任務(wù)——多線程操作,多線程和多線程的實現(xiàn) 線程間數(shù)據(jù)同步 帶
32、參數(shù)的線程線程池,10.4 線程池,“線程池”是可以用來在后臺執(zhí)行多個任務(wù)的線程集合。這使主線程可以自由地異步執(zhí)行其他任務(wù)。線程池通常用于服務(wù)器應(yīng)用程序。每個傳入請求都將分配給線程池中的一個線程,因此可以異步處理請求,而不會占用主線程,也不會延遲后續(xù)請求的處理。 一旦池中的某個線程完成任務(wù),它將返回到等待線程隊列中,等待被再次使用。這種重用使應(yīng)用程序可以避免為每個任務(wù)創(chuàng)建新線程的開銷。線程池通常具有最大線程數(shù)限制。如果所有線程都繁
33、忙,則額外的任務(wù)將放入隊列中,直到有線程可用時才能夠得到處理??梢詫崿F(xiàn)自己的線程池,但是通過 ThreadPool 類使用 .NET Framework 提供的線程池更容易一些。 ThreadPool 類提供一個線程池,該線程池可用于發(fā)送工作項、處理異步 I/O、代表其他線程等待以及處理計時器,其主要成員如下:,,QueueUserWorkItem(WaitCallback) 將方法排入隊列以便執(zhí)行。此方法在有線程池線程變得可用時執(zhí)行
34、。QueueUserWorkItem(WaitCallback, Object) 將方法排入隊列以便執(zhí)行,并指定包含該方法所用數(shù)據(jù)的對象。此方法在有線程池線程變得可用時執(zhí)行。,線程池給我們提供了一種多線程處理形式,處理過程中將任務(wù)添加到隊列,然后在創(chuàng)建線程后自動啟動這些任務(wù)。線程池線程都是后臺線程。每個線程都使用默認(rèn)堆棧大小,以默認(rèn)的優(yōu)先級運行,并處于多線程單元中。如果某個線程在托管代碼中空閑(如正在等待某個事件),則線程池將插入另一
35、個輔助線程來使所有處理器保持繁忙。如果所有線程池線程都始終保持繁忙,但隊列中包含掛起的工作,則線程池將在一段時間之后創(chuàng)建另一個輔助線程。,線程池特別適合于執(zhí)行一些需要多個線程的任務(wù)。使用線程池能夠優(yōu)化這些任務(wù)的執(zhí)行過程,從而提高吞吐量,它不僅能夠使系統(tǒng)針對此進程優(yōu)化該執(zhí)行過程,而且還能夠使系統(tǒng)針對計算機上的其他進程優(yōu)化該執(zhí)行過程。如果需要啟動多個不同的任務(wù),而不想分別設(shè)置每個線程的屬性,則可以使用線程池。ThreadPool是一個靜
36、態(tài)類,它沒有定義任何的構(gòu)造方法,我們只能夠使用它的靜態(tài)方法,它所要做的工作是在后臺進行的。使工作項的排隊和運行更容易,可以給工作者線程傳遞一個狀態(tài)對象。狀態(tài)對象是私有的作用域位于線程層,所以不需要進行同步。ThreadPool中的Thread不能手動取消,也不用手動開始。所以ThreadPool并不適用比較長的線程。你要做的只是把一個WaitCallback委托塞給ThreadPool,然后剩下的工作將由系統(tǒng)自動完成。系統(tǒng)會在Thre
37、adPool的線程隊列中一一啟動線程。當(dāng)線程池滿時,多余的線程會在隊列里排隊,當(dāng)線程池空閑時,系統(tǒng)自動調(diào)入排隊的線程,以保持系統(tǒng)利用率。,我們的程序中使用ThreadPool來進行一些比較耗時或者需要阻塞的操作。當(dāng)需要復(fù)雜的同步技術(shù),例如事件,或需要對一個現(xiàn)場表調(diào)用Join方法時線程池就不能滿足需求了。在以下情況中不宜使用ThreadPool而應(yīng)該使用單獨的Thread:線程需要指定優(yōu)先級線程的執(zhí)行時間較長線程在單獨的線程apar
38、tment中在線程執(zhí)行過程中對線程存在操作,如打斷,掛起等。通常是將計算密集型的操作放在worker線程池中運行,而線程池的大小會根據(jù)當(dāng)前的CPU使用量自動調(diào)整,通過下面兩個方法,我們可以設(shè)置線程池的大小:ThreadPool.SetMaxThreads(10, 200);ThreadPool.SetMinThreads(2, 40);兩個參數(shù)分別是WorkThread和IO thread的限制。看了這么多關(guān)于線程池的知識,
溫馨提示
- 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. 眾賞文庫僅提供信息存儲空間,僅對用戶上傳內(nèi)容的表現(xiàn)方式做保護處理,對用戶上傳分享的文檔內(nèi)容本身不做任何修改或編輯,并不能對任何下載內(nèi)容負(fù)責(zé)。
- 6. 下載文件中如有侵權(quán)或不適當(dāng)內(nèi)容,請與我們聯(lián)系,我們立即糾正。
- 7. 本站不保證下載資源的準(zhǔn)確性、安全性和完整性, 同時也不承擔(dān)用戶因使用這些下載資源對自己和他人造成任何形式的傷害或損失。
最新文檔
- 統(tǒng)籌兼顧,齊頭并進
- 打好扶貧精準(zhǔn)牌齊頭并進奔小康
- “來了就不想走”的魅力 工銀瑞信,人才、業(yè)績、規(guī)模齊頭并進
- 保證完成任務(wù)表態(tài)發(fā)言
- 執(zhí)行如何完成任務(wù)的學(xué)問
- 20180918-興業(yè)證券-興業(yè)證券聲吶行業(yè)研究:軍民市場齊頭并進,打造水下信息世界
- 操作系統(tǒng)課程設(shè)計--- 多線程管理與線程通信
- 充分發(fā)揮基層黨組織的戰(zhàn)斗堡壘作用 確保各項工作齊頭并進
- 電力行業(yè)2022年三季報業(yè)績綜述:水“枯”火“熱”核風(fēng)光齊頭并進
- linux多線程編程
- vxWorks操作系統(tǒng)的多線程實現(xiàn)研究.pdf
- (11)招聘面試工作完成任務(wù)記錄
- linux操作系統(tǒng)下的多線程編程詳細解析
- 教育行業(yè)博實樂2018財報點評營收增速提高,調(diào)整后盈利增強,內(nèi)生與外延齊頭并進
- 銀行業(yè)利率并軌與非對稱降息齊頭并進價格型貨幣政策調(diào)控方式猜想-20190320-16頁
- java多線程編程詳解
- 多線程的內(nèi)存調(diào)度.pdf
- 固定資產(chǎn)投資約談表態(tài)發(fā)言材料(未完成任務(wù))
- 執(zhí)行工程計劃及目標(biāo)預(yù)算超目標(biāo)完成任務(wù)獎勵準(zhǔn)則
- 不錯的delphi多線程編程教程
評論
0/150
提交評論