版權說明:本文檔由用戶提供并上傳,收益歸屬內(nèi)容提供方,若內(nèi)容存在侵權,請進行舉報或認領
文檔簡介
1、第七章 多線程程序設計,7.1 創(chuàng)建線程 7.2 多個線程互斥 7.3 生產(chǎn)者線程和消費者線程的同步,如果在一個程序中,有多個工作要同時做,可以采用多線程。在Windows操作系統(tǒng)中可以運行多個程序,把一個運行的程序叫做一個進程。一個進程又可以有多個線程,每個線程輪流占用CPU的運行時間,Windows操作系統(tǒng)將時間分為時間片,一個線程用完一個時間片后,操作系統(tǒng)將此線程掛起,將另一個線程喚醒,使其使用下一個時間片,操作系統(tǒng)不斷的把線程掛起,喚醒,再掛起,再喚醒,如此反復,由于現(xiàn)在CPU的速度比較快,給人的感覺象是多個線程同時執(zhí)行。Windows操作系統(tǒng)中有很多這樣的例子,例如復制文件時,一方面
2、在進行磁盤的讀寫操作,同時一張紙不停的從一個文件夾飄到另一個文件夾,這個飄的動作實際上是一段動畫,兩個動作是在不同線程中完成的,就像兩個動作是同時進行的。又如Word程序中的拼寫檢查也是在另一個線程中完成的。每個進程最少有一個線程,叫主線程,是進程自動創(chuàng)建的,每進程可以創(chuàng)建多個線程。,Process類,Process類 Process類位于System.Diagnostics名稱空間下,它專門用于完成系統(tǒng)進程的管理任務。 可以在本地計算機上啟動和停止進程,也可以向進程查詢特定類型的信息。在遠程計算機上,無法啟動和停止進程,但可以查詢進程的相關信息。在對進程進行操作時,首先要創(chuàng)建Process類
3、的實例,其次還需要設置其對象成員的StartInfo屬性,最后調(diào)用它的Start方法。,例.啟動、停止和觀察進程,1. 新建一個名為ProcessExample的Windows應用程序。 2. 從工具箱中將Process組件拖放到設計窗體。 3. 添加名稱空間 : using System.Diagnostics; using System.Threading; 4. 添加“啟動記事本”、“停止記事本”和“觀察所有進程”三個按鈕,并添加Click事件代碼: private void buttonStart_Click(object sender, EventArgs e) process1.S
4、tartInfo.FileName = notepad.exe; /啟動Notepad.exe進程. process1.Start(); ,private void buttonStop_Click(object sender, EventArgs e) /創(chuàng)建新的Process組件的數(shù)組,并將它們與指定的進程名稱(Notepad)的所有進程資源相關聯(lián). Process myprocesses; myprocesses = Process.GetProcessesByName(Notepad); foreach (Process instance in myprocesses) /設置終止當前
5、線程前等待1000毫秒 instance.WaitForExit(1000); instance.CloseMainWindow(); private void buttonView_Click(object sender, EventArgs e) listBox1.Items.Clear(); /創(chuàng)建Process類型的數(shù)組,并將它們與系統(tǒng)內(nèi)所有進程相關聯(lián),Process processes; processes = Process.GetProcesses(); foreach (Process p in processes) /由于訪問Idle的StartTime會出現(xiàn)異常,所以將其排
6、除在外 if (p.ProcessName != Idle) /將每個進程名和進程開始時間加入listBox1中 this.listBox1.Items.Add( string.Format(0,-301:h:m:s, p.ProcessName, p.StartTime); ,超級鏈接到微軟網(wǎng)站 : System.Diagnostics.Process.Start( 打開一個窗口,列出C盤根目錄下的文件及文件夾 : System.Diagnostics.Process.Start(C:/);,7.1 創(chuàng)建線程,本節(jié)介紹線程類(Thread)的屬性和方法以及如何創(chuàng)建線程。,7.1.1 線程類(
7、Thread)的屬性和方法,線程類在命名空間System.Threading中定義的,因此如果要創(chuàng)建多線程,必須引入命名空間System.Threading。Thread類的常用屬性和方法如下: 屬性Priority:設置線程優(yōu)先級,有5種優(yōu)先級類別:AboveNormal(稍高)、BelowNormal(稍低)、Normal(中等,默認值)、Highest(最高)和Lowest(最低)。例如語句myThread.Priority=ThreadPriority.Highest設置線程myThread的優(yōu)先級為最高。優(yōu)先級高的線程先運行,只有優(yōu)先級高的線程停止、休眠或暫停時,低優(yōu)先級的線程才能運
8、行。,構造函數(shù):Thread(new ThreadStart(線程中要執(zhí)行的無參數(shù)方法名),參數(shù)中指定的方法需要程序員自己定義,這個方法完成線程所要完成的任務,退出該方法,線程結束。該方法必須為公有void類型的方法,無參數(shù)。如果希望有參數(shù),可使用C#2.0中新構造函數(shù):Thread(new ParameterizedThreadStart(線程中要執(zhí)行的有參數(shù)方法名)。 方法Start():建立線程類對象后,線程處于未啟動狀態(tài),這個方法使線程改變?yōu)榫途w狀態(tài),如果能獲的CPU的運行時間,線程變?yōu)檫\行狀態(tài)。 方法IsAlive():判斷線程對象是否存在,=true,線程存在。,方法Abort()
9、:撤銷線程對象。不能撤銷一個已不存在的線程對象,因此在撤銷一個線程對象前,必須用方法IsAlive()判斷線程對象是否存在。 靜態(tài)方法Sleep():線程休眠參數(shù)設定的時間,單位為毫秒,此時線程處于休眠狀態(tài)。線程休眠后,允許其他就緒線程運行。休眠指定時間后,線程變?yōu)榫途w狀態(tài)。 方法Suspend()和Resume():Suspend()方法使線程變?yōu)閽炱馉顟B(tài)。Resume方法使掛起線程變?yōu)榫途w狀態(tài),如能獲的CPU的運行時間,線程變?yōu)檫\行狀態(tài)。如線程多次被掛起,調(diào)用一次Resume()方法就可以把線程喚醒。由于不安全C#2.0建議不使用這兩個函數(shù)。,7.1.2 創(chuàng)建線程,【例7.1】本例使用線程
10、類Thread創(chuàng)建一個新的線程,在標簽控件中顯示該線程運行的時間。在窗體放置2個按鈕,單擊按鈕完成新建和停止線程的功能。 新建項目。在窗體中放置2個按鈕和1個標簽控件(label1)。button1的屬性Text=“新線程”, Enabled=true。button2的屬性Text=“撤銷”, Enabled=false。 在Form1.cs頭部增加語句: using System.Threading。 為Form1類中聲明一個代表類dFun、定義一個類dFun的變量和線程類變量:,delegate void dFun(string text); dFun dFun1; /dFun類變量 pr
11、ivate Thread thread; /線程類變量 為標題為“新線程”的按鈕(button1)增加單擊事件處理函數(shù)如下: private void button1_Click(object sender, EventArgs e) thread=new Thread(new ThreadStart(fun); label1.Text=0;/運行時間從0開始 thread.Start(); button1.Enabled=false; button2.Enabled=true; ,為標題為“撤銷”的按鈕(button2)增加單擊事件處理函數(shù)如下: private void button2_C
12、lick(object sender, EventArgs e) if(thread.IsAlive) thread.Abort();/撤銷線程對象 button1.Enabled=true; button2.Enabled=false; ,C#線程模型允許將任何一個void類型的公有方法(靜態(tài)或非靜態(tài))作為線程方法,因此允許在任何一個類(不要求這個類是某個類的子類)中定義線程方法,而且同一個類中可以定義多個線程方法。C#2.0不允許在此函數(shù)中直接修改線程外控件屬性,這是防止多個線程同時修改同一控件的同一屬性發(fā)生錯誤,必須使用控件的Invoke方法修改線程外控件屬性,Invoke方法有兩個參數(shù)
13、,參數(shù)1是修改控件屬性的方法的代表, 參數(shù)2是object數(shù)組,是傳遞給參數(shù)1代表的方法的參數(shù)。為Form1類定義一個線程方法如下:,public void fun() while(true)/退出該方法,線程結束 int x=Convert.ToInt32(label1.Text); x+; string s=Convert.ToString(x); label1.Invoke(dFun1,new objects); Thread.Sleep(1000); /線程休眠1秒鐘 為Form1類定義一個修改label1.Text的方法如下:,private void SetText(string
14、text) label1.Text = text; 在Form1類的構造函數(shù)的最后增加如下語句: dFun1=new dFun(SetText); 在關閉程序之前,必須撤銷線程對象。為主窗體的Closing事件增加事件處理函數(shù)如下: private void Form1_FormClosing(object sender, FormClosingEventArgs e) if(thread.IsAlive) thread.Abort(); 編譯運行,單擊標題為新線程的按鈕,新線程開始,計數(shù)器從0開始計數(shù)。單擊標題為撤銷的按鈕,線程對象被撤銷,計數(shù)器停止計數(shù)。,7.1.3 進度條(Progres
15、sBar)控件,進度條(ProgressBar)控件經(jīng)常用來顯示一個任務的進度。有時,要完成一個長時間的任務,例如一個軟件的安裝,如果沒有任何提示,使用者可能分不清任務是在進行中,還是死機了,可以使用進度條顯示安裝進度,表示安裝正在進行。進度條常用屬性如下: 屬性Maximum和Minimum:進度條代表的最大值和最小值(整數(shù)),默認值分別為100,0。 屬性Step:變化的步長,默認值為10。 屬性Value:進度條當前位置代表的值。修改該值,達到一個Step,進度增加一格。,7.1.3 用線程控制進度條,有時需要建立多個線程,每個線程要實現(xiàn)的功能基本相同,但有個別參數(shù)不同,例如,每個線程完
16、成同樣的任務,但控制的對象不同??墒褂肅#2.0中定義的線程類構造函數(shù)Thread(new ParameterizedThreadStart()創(chuàng)建新線程,處為一個實現(xiàn)線程所要求任務的方法,該方法只允許有1個object類型參數(shù),可用參數(shù)傳遞不同對象。實現(xiàn)方法見下例。 【例7.2】建立兩個線程,分別控制兩個進度條(ProgressBar)控件,每個進度條的屬性Value變化的速率不一樣。具體實現(xiàn)步驟如下,運行效果如圖。,新建項目。在Form1.cs頭部增加語句:using System.Threading。 在窗體中放置2個進度條(ProgressBar)控件。屬性Name分別為Progres
17、sBar1、ProgressBar2 。 為Form1類中聲明一個結構、代表類dFun、定義一個類dFun的變量和線程類變量: 結構定義,由于要傳遞兩個參數(shù),定義結構代表兩個參數(shù) struct Fargs public ProgressBar PB;/線程控制的對象 public int SleepT; /線程休眠時間,delegate void dFun(ProgressBar p); dFun dFun1; /Fun類變量 private Thread thread1;/線程類變量 private Thread thread2; Fargs Frags1; /結構變量 為Form1類定義一
18、個線程方法如下(注意只能有一個object類參數(shù)): public void fun(object data) Fargs Frags2 = (Fargs)data; ProgressBar p1 = Frags2.PB; int SleepTime = Frags2.SleepT; while (p1.Value 100) p1.Invoke(dFun1, new object p1 ); Thread.Sleep(SleepTime); 5.為Form1類定義一個修改進度條的屬性Value的方法如下:,private void SetValue(ProgressBar p2) p2.Val
19、ue += 1; 6.在Form1類的Load事件增加事件函數(shù)如下(此處代碼不能放在構造函數(shù)中): private void Form1_Load(object sender, EventArgs e) dFun1 = new dFun(SetValue); thread1 = new Thread(new ParameterizedThreadStart(fun); thread2 = new Thread(new ParameterizedThreadStart(fun); Frags1.PB = progressBar1; Frags1.SleepT = 100; thread1.Sta
20、rt(Frags1); /注意如何為fun方法傳遞參數(shù) Frags1.PB = progressBar2; Frags1.SleepT = 200; thread2.Start(Frags1); ,7.為主窗體的Closing事件增加事件處理函數(shù)如下: private void Form1_FormClosing(object sender, FormClosingEventArgs e) if(thread1.IsAlive) thread1.Abort(); if(thread2.IsAlive) thread2.Abort(); 8.編譯,運行,可以看到兩個進度條以不同的速度前進,當進度
21、條被添滿,線程停止。,7.1.5 BackgroundWorker組件,Windows應用程序如需要執(zhí)行長時間的后臺操作(例如Word程序的拼寫檢查),可以建立一個優(yōu)先級最低的線程完成這樣的工作。編寫這樣線程代碼可能是一項艱巨而又耗時的工作。在VS2005中,可以使用BackgroundWorker控件簡化編程??丶S脤傩院头椒ㄈ缦拢?方法RunWorkerAsync(object):啟動線程,參數(shù)將傳遞給線程DoWork事件處理函數(shù)。 方法CancelAsync():結束線程。 事件DoWork:希望在線程中完成的工作代碼放到此事件處理函數(shù)中。 事件RunWorkerCompleted:線
22、程結束引發(fā)的事件。通過事件函數(shù)參數(shù)2獲得退出的原因。,7.2 多個線程互斥,多個線程同時修改共享數(shù)據(jù)可能發(fā)生錯誤。假設2個線程分別監(jiān)視2個入口進入的人數(shù),每當有人通過入口,線程用C#語句對總人數(shù)變量執(zhí)行加1操作。一條C#語句可能包含若干機器語言語句,假設C#語句加1操作包含的機器語言語句是:取總人數(shù),加1,再存回。操作系統(tǒng)可以在一條機器語言語句結束后,掛起運行的線程。如當前總人數(shù)為5,線程1運行,監(jiān)視到有人通過入口,取出總人數(shù)(=5)后,線程1時間用完掛起。線程2喚醒,也監(jiān)視到有人通過入口,并完成了總人數(shù)加1并送回的操作,總人數(shù)為6,線程2掛起。線程1喚醒,對已取出的總人數(shù)(此時為5)加1,存
23、回去,總人數(shù)應為7,實為6,少算一個。為了防止此類錯誤,在一個線程修改共享資源(例如上例的總人數(shù)變量)時,不允許其他線程對同一共享資源進行修改,這叫線程的互斥。這樣的實例很多,例如計算機中的許多外設,網(wǎng)絡中的打印機等都是共享資源,只允許一個進程或線程使用。,7.2.1多個線程同時修改共享數(shù)據(jù)可能發(fā)生錯誤,【例7.4】下邊的例子模擬2個線程同時修改同一個共享數(shù)據(jù)時可能發(fā)生的錯誤。 1.新建項目。在Form1.cs頭部增加語句: using System.Threading。 2.為Form1類定義2個線程類變量:Thread thread1,thread2。定義整形變量:int num=0。 3
24、.在窗體中放置一個標簽和按鈕控件,按鈕的事件處理函數(shù)如下: private void button1_Click(object sender, EventArgs e) label1.Text = num.ToString(); 4.為Form1類構造函數(shù)增加語句如下: thread1= new Thread(new ThreadStart(Fun1); thread2= new Thread(new ThreadStart(Fun2); thread1.Start(); thread2.Start();,5.為Form1類中定義Fun1()和Fun2()方法如下: public void F
25、un1() int k,n; for(k=0;k4;k+) n=num;/取出num,可以把把num想象為總人數(shù) n+;/加1 /模擬復雜的費時運算,在此期間,有可能時間片用完 Thread.Sleep(20); num=n;/存回num Thread.Sleep(50); /退出該方法,線程結束,public void Fun2() int k,n; for(k=0;k4;k+) n=num; n+; Thread.Sleep(10); num=n; Thread.Sleep(100); 6.編譯運行,單擊按鈕,標簽控件應顯示8,實際運行多次,顯示的數(shù)要小于8。,7.2.2 用Lock語句實
26、現(xiàn)互斥,Lock語句的形式如下:lock(e)訪問共享資源的代碼。其中e指定要鎖定的對象,鎖定該對象內(nèi)所有臨界區(qū),必須是引用類型,一般為this。Lock語句將訪問共享資源的代碼標記為臨界區(qū)。臨界區(qū)的意義是:假設線程1正在執(zhí)行e對象的臨界區(qū)中的代碼時,如其他線程也要求執(zhí)行這個e對象的任何臨界區(qū)中代碼,將被阻塞,一直到線程1退出臨界區(qū)。 【例7.5】用C#語句Lock實現(xiàn)互斥。修改例7.4中的Fun1()和Fun2()方法如下:,public void Fun1() int k,n; for(k=0;k4;k+) lock(this)/這里的this是Form1類的對象 n=num;/這對大括號
27、中代碼為this的臨界區(qū) n+;/this的臨界區(qū)包含兩部分,函數(shù)Fun1和Fun2中的臨界區(qū) Thread.Sleep(10); num=n; Thread.Sleep(50); /退出該方法,線程結束,public void Fun2() int k,n; for(k=0;k4;k+) /如有線程進入此臨界區(qū),其他線程就不能進入這個臨界區(qū) lock(this) n=num;/也不能進入前邊的臨界區(qū) n+; Thread.Sleep(10); num=n; Thread.Sleep(100); 編譯運行,單擊按鈕標簽控件應顯示8。如果有多個共享數(shù)據(jù)區(qū),使用此方法不太方便。,7.2.3 用Mu
28、tex類實現(xiàn)互斥,可以使用Mutex類對象保護共享資源(如上例中的總人數(shù)變量)不被多個線程同時訪問。Mutex類WaitOne方法和ReleaseMutex方法之間代碼是互斥體,這些代碼要訪問共享資源。Mutex類的WaitOne方法分配互斥體訪問權,該方法只向一個線程授予對互斥體的獨占訪問權。如果一個線程獲取了互斥體,則要獲取該互斥體的第二個線程將被掛起,直到第一個線程用ReleaseMutex方法釋放該互斥體。 【例7.6】使用Mutex類對象實現(xiàn)互斥。修改例7.4,為Form1類增加私有Mutex類變量:private Mutex mut。在Form1類構造函數(shù)中增加語句:mut=new
29、 Mutex();該句位置必須在建立線程語句之前。修改例7.4中的兩個Fun1()和Fun2()方法如下:,public void Fun1() int k,n; for(k=0;k4;k+) mut.WaitOne();/等待互斥體訪問權 n=num;/ mut.WaitOne()和mut.ReleaseMutex()之間是互斥體 n+;/Mutex類對象mut的互斥體包含兩部分,函數(shù)Fun1和Fun2中的互斥體 Thread.Sleep(10);/有線程進入一個互斥體,其他線程不能進入任何一個互斥體 num=n; mut.ReleaseMutex();/釋放互斥體訪問權 Thread.Sl
30、eep(50); /退出該方法,線程結束,public void Fun2() int k,n; for(k=0;k4;k+) mut.WaitOne(); n=num; n+; Thread.Sleep(10); num=n; mut.ReleaseMutex(); Thread.Sleep(100); 編譯,運行,標簽控件顯示8。如果有多個共享數(shù)據(jù)區(qū),可以定義多個Mutex類對象。,7.2.4 用Monitor類實現(xiàn)互斥,也可以使用Monitor類保護共享資源不被多個線程或進程同時訪問。Monitor類通過向單個線程授予對象鎖來控制對對象的訪問。只有擁有對象鎖的線程才能執(zhí)行臨界區(qū)的代碼,此
31、時其他任何線程都不能獲取該對象鎖。只能使用Monitor類中的靜態(tài)方法,不能創(chuàng)建Monitor類的實例。Monitor類中的靜態(tài)方法主要有: 方法Enter:獲取參數(shù)指定對象的對象鎖。此方法放在臨界區(qū)的開頭。如其他線程已獲取對象鎖,則該線程將被阻塞,直到其他線程釋放對象鎖,才能獲取對象鎖。,方法Wait:釋放參數(shù)指定對象的對象鎖,以便允許其他被阻塞的線程獲取對象鎖。該線程進入等待狀態(tài),等待狀態(tài)必須由其他線程用方法Pulse或PulseAll喚醒,使等待狀態(tài)線程變?yōu)榫途w狀態(tài)。 方法Pulse和PulseAll:向等待線程隊列中第一個或所有等待參數(shù)指定對象的對象鎖的線程發(fā)送信息,占用對象鎖的線程準
32、備釋放對象鎖。執(zhí)行方法Exit后將釋放對象鎖。 方法Exit:釋放參數(shù)指定對象的對象鎖。此操作還標記受對象鎖保護的臨界區(qū)的結尾。 使用Monitor類實現(xiàn)互斥也很簡單,請讀者修改例7_2_1,使用Monitor類實現(xiàn)互斥。Monitor類主要用來實現(xiàn)生產(chǎn)者和消費者關系中的線程的同步,具體例子見下一節(jié)。,7.3 生產(chǎn)者線程和消費者線程的同步,在生產(chǎn)者和消費者關系中,生產(chǎn)者線程產(chǎn)生數(shù)據(jù),并把數(shù)據(jù)存到公共數(shù)據(jù)區(qū),消費者線程使用數(shù)據(jù),從公共數(shù)據(jù)區(qū)取出數(shù)據(jù)。顯然如果公共數(shù)據(jù)區(qū)只能存一個數(shù)據(jù),那么在消費者線程取出數(shù)據(jù)前,生產(chǎn)者線程不能放新數(shù)據(jù)到公共數(shù)據(jù)區(qū),否則消費者線程將丟失數(shù)據(jù)。同樣只有生產(chǎn)者線程把數(shù)據(jù)
33、已經(jīng)放到公共數(shù)據(jù)區(qū),消費者線程才能取出數(shù)據(jù),否則消費者線程不能取數(shù)據(jù)。這些就是所謂的生產(chǎn)者和消費者關系,必須要求生產(chǎn)者線程和消費者線程同步。,7.3.1 生產(chǎn)者線程和消費者線程不同步可能發(fā)生錯誤,【例7.7】下邊的例子模擬生產(chǎn)者線程和消費者線程不同步可能發(fā)生錯誤。有一個公共變量,要求生產(chǎn)者線程順序放1到4到這個公共變量中,每放一個變量,消費者線程取出這個數(shù)求和,最后把和顯示出來,顯然和應為10。如不采取同步措施,和的結果不正確。 1.新建項目。在Form1.cs頭部增加語句: using System.Threading。 2.為Form1類定義2個線程類變量:Thread thread1,thread2。 3.為Form1類定義2個整形變量:int sum=0,x=-1。 4.在窗體中放置一個標簽和按鈕控件,按鈕的事件處理函數(shù)如下: private void
溫馨提示
- 1. 本站所有資源如無特殊說明,都需要本地電腦安裝OFFICE2007和PDF閱讀器。圖紙軟件為CAD,CAXA,PROE,UG,SolidWorks等.壓縮文件請下載最新的WinRAR軟件解壓。
- 2. 本站的文檔不包含任何第三方提供的附件圖紙等,如果需要附件,請聯(lián)系上傳者。文件的所有權益歸上傳用戶所有。
- 3. 本站RAR壓縮包中若帶圖紙,網(wǎng)頁內(nèi)容里面會有圖紙預覽,若沒有圖紙預覽就沒有圖紙。
- 4. 未經(jīng)權益所有人同意不得將文件中的內(nèi)容挪作商業(yè)或盈利用途。
- 5. 人人文庫網(wǎng)僅提供信息存儲空間,僅對用戶上傳內(nèi)容的表現(xiàn)方式做保護處理,對用戶上傳分享的文檔內(nèi)容本身不做任何修改或編輯,并不能對任何下載內(nèi)容負責。
- 6. 下載文件中如有侵權或不適當內(nèi)容,請與我們聯(lián)系,我們立即糾正。
- 7. 本站不保證下載資源的準確性、安全性和完整性, 同時也不承擔用戶因使用這些下載資源對自己和他人造成任何形式的傷害或損失。
最新文檔
- 第30課《系統(tǒng)安全需升級》測試題2025-2026學年人教版八年級信息科技全一冊
- 《GB-T 24438.3-2012自然災害災情統(tǒng)計 第3部分:分層隨機抽樣統(tǒng)計方法》專題研究報告
- 《GBT 21595-2008 危險品便攜式罐體撞擊試驗方法》專題研究報告
- 《GBT 14993-2008轉動部件用高溫合金熱軋棒材》專題研究報告
- 《GB 4706.85-2008家用和類似用途電器的安全 紫外線和紅外線輻射皮膚器具的特殊要求》專題研究報告
- 道路危險運輸安全培訓課件
- 道路交通安全培訓素材課件
- 道路交通培訓課件
- 2025-2026年蘇教版八年級語文上冊期末題庫試題附答案
- 迪奧項鏈介紹
- 《中國臨床腫瘤學會(csco)小細胞肺癌診療指南(2025版)》
- 2025至2030中國半導體AMC過濾器行業(yè)競爭優(yōu)勢及前景趨勢預判報告
- 鄉(xiāng)鎮(zhèn)高層滅火救援疏散應急演練方案及流程
- 五恒系統(tǒng)節(jié)能環(huán)保施工技術規(guī)范與優(yōu)化研究
- 大學期末考試思政題庫及答案
- 師徒結對活動記錄表-師傅
- have與has的用法微課課件
- 如何做員工考勤管理制度
- 大學形勢政策課件
- 城市供水管道施工重難點分析及改進措施
- 2025年南京市事業(yè)單位教師招聘體育學科專業(yè)知識歷年真題解析試卷
評論
0/150
提交評論