久久国产成人av_抖音国产毛片_a片网站免费观看_A片无码播放手机在线观看,色五月在线观看,亚洲精品m在线观看,女人自慰的免费网址,悠悠在线观看精品视频,一级日本片免费的,亚洲精品久,国产精品成人久久久久久久

分享

C#多線程(一)

 昵稱10504424 2014-03-28

1,、定義

線程是操作系統(tǒng)分配CPU時間片的基本單位,每個運行的引用程序為一個進程,,這個進程可以包含一個或多個線程,。

線程是進程中的執(zhí)行流程,每個線程可以得到一小段程序的執(zhí)行時間,,在單核處理器中,,由于切換線程速度很快因此感覺像是線程同時允許,其實任意時刻都只有一個線程運行,,但是在多核處理器中,,可以實現(xiàn)混合時間片和真實的并發(fā)執(zhí)行。但是由于操作系統(tǒng)自己的服務或者其他應用程序執(zhí)行,,也不能保證一個進程中的多個線程同時運行,。

線程被一個CLR委托給操作系統(tǒng)的進程協(xié)調(diào)函數(shù)管理,確保所有線程都可以被分配適當?shù)膱?zhí)行時間,,同時保證在等待或阻止的線程不占用執(zhí)行時間,。

2、理解

線程與進程的關鍵區(qū)別是:進程是彼此隔離的,,進程是操作系統(tǒng)分配資源的基本單位,,而同一個進程中的多個線程是共享該進程內(nèi)存堆區(qū)(Heap)的數(shù)據(jù)的,可以進行直接的數(shù)據(jù)共享,。但是對于同一進程內(nèi)的不同線程維護各自的內(nèi)存棧(Stack),,因此各線程的局部變量是隔離的。通過下面的例子可以看出,。

 

[csharp] view plaincopyprint?在CODE上查看代碼片派生到我的代碼片
  1. static void Main(string[] args)
  2. {
  3. Thread t = new Thread(Write);
  4. t.Start();
  5. Write();
  6. Console.ReadKey();
  7. }

  8. static void Write()
  9. {
  10. for (int i = 0; i < 5; i++)
  11. Console.Write("@");
  12. }


結(jié)果輸出的是10個“@”,,在兩個線程中都有局部變量i,是彼此隔離的,。但是對于共享的引用變量和靜態(tài)數(shù)據(jù),,多個線程是會產(chǎn)生不可預知的結(jié)果的,這里共享的數(shù)據(jù)也就是“臨界數(shù)據(jù)”,,從而引發(fā)了線程安全的概念,。

 

 

[csharp] view plaincopyprint?在CODE上查看代碼片派生到我的代碼片
  1. static bool done;
  2. static void Main(string[] args)
  3. {
  4. Thread t = new Thread(Write);
  5. t.Start();
  6. Write();
  7. Console.ReadKey();
  8. }

  9. static void Write()
  10. {
  11. if (!done)
  12. {
  13. done = true;
  14. Console.Write("@");
  15. }
  16. }


這里輸出的只有一個字符,但是很可能在極少數(shù)情況下會出現(xiàn)輸出兩個字符的情況,,而且這是不可預知的,。但是,對于共享的引用就不會出現(xiàn)這種情況,。

 

二,、線程使用情形

 

  • 客戶端應用程序保持對用戶的響應:由于某些應用程序的特定需求,多線程程序一般用來執(zhí)行需要非常耗時的操作,,此時使用主線程創(chuàng)建工作線程在后臺執(zhí)行耗時的任務,,而主線程保持運行,例如保持與用戶的交互(更新進度條,、顯示提示文字等),,這樣可以防止由于程序耗時而被操作系統(tǒng)提示“無響應”而被用戶強制關閉進程。
  • 及時處理請求:對于Web應用程序,,主線程相應客戶端用戶的請求,,返回數(shù)據(jù)的同時,工作線程從數(shù)據(jù)庫選出最新數(shù)據(jù),。這樣可以對某些實時性要求高的應用非常有效,,同時可以查詢工作量被單獨線程分開執(zhí)行,特別是在多核處理器上,,可以提高程序的性能,。同時對于服務器需要處理多種類型的請求的時候,如ASP.NET,、WCF,、Remoting等,從而可以實現(xiàn)并發(fā)響應,。
  • 防止一個線程長時間沒有響應而阻塞CPU來提高效率:例如WebService服務,,對于沒有用戶交互界面的訪問,在等待提供webservice服務(比較耗時)的電腦的響應的同時可以執(zhí)行其他工作,,以提高效率,。

 

問題:

多線程的問題是使程序中的多個線程的交互變得過于復雜,會帶來較長的開發(fā)時間和間歇性或非重復性的bug,。同時線程數(shù)目不能太多,,否則頻繁的分配和切換線程會帶來資源和CPU的開銷,一般有一個到兩個工作線程就足夠,。

三,、C#中的線程

C#中主要使用Thread類進行線程操作,位于System.Threading命名空間下,,提供了一系列進行多線程編程的類和接口,,有線程同步和數(shù)據(jù)訪問的Mutex、Monitor,、Interlocked和AutoResetEvent類,,以及ThreadPool類和Timer類等。

首先使用new Thread()創(chuàng)建出新的線程,然后調(diào)用Start方法使得線程進入就緒狀態(tài),,得到系統(tǒng)資源后就執(zhí)行,,在執(zhí)行過程中可能有等待、休眠,、死亡和阻塞四種狀態(tài),。正常執(zhí)行結(jié)束時間片后返回到就緒狀態(tài)。如果調(diào)用Suspend方法會進入等待狀態(tài),,調(diào)用Sleep或者遇到進程同步使用的鎖機制而休眠等待,。具體過程如下圖所示:

Thread類主要用來創(chuàng)建并控制線程,設置線程的狀態(tài),、優(yōu)先級等,。創(chuàng)建線程的時候使用ThreadStart委托或者ParameterizedThreadStart委托來執(zhí)行線程所關聯(lián)的部分代碼(也就是工作線程的運行代碼)。

Thread類屬性
屬性 說明
CurrentThread 獲取當前正在運行的線程
IsAlive 獲取當前線程的執(zhí)行狀態(tài)
Name 獲取或設置線程的名稱
Priority 獲取或設置線程的優(yōu)先級
ThreadState 獲取包含當前線程狀態(tài)的值
Thread類常用方法
方法 說明
Abort 調(diào)用此方法的線程引發(fā)ThreadAbortException
終止線程
Join 阻止調(diào)用線程,,知道某個線程終止時為止
Resume 繼續(xù)已掛起的線程
Sleep 將線程阻止指定的毫秒數(shù)
Start 將線程安排被進行執(zhí)行
Suspent 掛起線程,,如果已經(jīng)掛起則不起作用

 

四、創(chuàng)建與運行設置

1,、創(chuàng)建

 

使用Thread類的構造函數(shù)創(chuàng)建線程的時候,,需要傳遞一個新線程開始執(zhí)行的代碼塊,提供了使用無參數(shù)的TheadStart委托和帶有一個參數(shù)的ParameterizedTheadStart委托,。他們的定義如下:

 

[csharp] view plaincopyprint?在CODE上查看代碼片派生到我的代碼片
  1. public delegate void ThreadStart();
  2. public delegate void ParameterizedThreadStart(object obj);

任何時候C#使用上述兩個委托中的一個自動進行線程的創(chuàng)建,。

 

 

[csharp] view plaincopyprint?在CODE上查看代碼片派生到我的代碼片
  1. static void Main()
  2. {
  3. Thread t = new Thread(new TheadStart(Go));
  4. t.Start();
  5. Go();
  6. }
  7. static void Go()
  8. {
  9. Console.Write("hello!");
  10. }

上述方式不傳遞參數(shù),可以使用new Thead(Go)的方式直接創(chuàng)建,,此時C#會在編譯時自動匹配使用的是ThreadStart委托創(chuàng)建的,。下面可以進行傳遞參數(shù)創(chuàng)建線程。

[csharp] view plaincopyprint?在CODE上查看代碼片派生到我的代碼片
  1. static void Main()
  2. {
  3. Thread t = new Thread(Go);
  4. t.Start("hello");
  5. Go();
  6. }
  7. static void Go(object msg)
  8. {
  9. string message = (string)msg;
  10. Console.Write(message);
  11. }

 

此時實際在編譯時使用的new Thread(new ParameterizedThreadStart(Go("hello")))創(chuàng)建的,,上述使用Start方法傳遞的參數(shù)會默認采用這種方式構建,。

第二種方法是使用Lambda表達式:

 

[csharp] view plaincopyprint?在CODE上查看代碼片派生到我的代碼片
  1. new Thread( () => Go("hello") );

第三種方法是使用匿名方法:

 

 

[csharp] view plaincopyprint?在CODE上查看代碼片派生到我的代碼片
  1. new Thread( () => {
  2. Console.Write("hello world!");
  3. ......
  4. }).Start();

注意問題:使用Lambda表達式的時候會存在變量捕獲的問題,如果捕獲的變量是共享的,,會出現(xiàn)線程不安全的問題,。看下面的例子:

 

 

[csharp] view plaincopyprint?在CODE上查看代碼片派生到我的代碼片
  1. static void Main(string[] args)
  2. {
  3. for (int i = 0; i < 10; i++)
  4. new Thread(() => Write(i)).Start();
  5. Console.ReadKey();
  6. }

  7. static void Write(object obj)
  8. {
  9. string msg = Convert.ToString(obj);
  10. Console.Write(msg);
  11. }

上述由于使用Lambda表達式傳遞參數(shù),,在for循環(huán)的作用域內(nèi),,新建的十個線程共享了局部變量i,傳遞進入i參數(shù)可能被多個線程已經(jīng)修改,,因此每次輸出結(jié)果都是不確定的,,兩次結(jié)果如下:

 



上述問題,可以使用在循環(huán)體內(nèi)使用一個tmp變量保存每次的變量i值,,這樣輸出的就是0到9這十個數(shù),。因為使用tmp變量之后的代碼可以用下面的來理解:

 

[csharp] view plaincopyprint?在CODE上查看代碼片派生到我的代碼片
  1. int i = 0;
  2. int tmp = i;
  3. new Thread(()=>Write(tmp)).Start();

  4. int i = 1;
  5. int tmp = i;
  6. new Thread(()=>Write(tmp)).Start();

  7. ...

上述使用Lambda表達式傳遞參數(shù)的問題,,使用Start方法傳遞參數(shù)也會出現(xiàn)這樣的線程不安全的問題,需要使用特殊的線程同步手段進行避免,。

 

2,、設置

通過使用Thread.CurrentThread屬性獲取正在運行的線程對象。每個線程都有一個Name屬性,,可以設置和修改,,但是只能設置一次,。這樣可在調(diào)試窗口看到每個線程的工作狀態(tài),,便于調(diào)試。

線程有前臺和后臺之分,,可以使用IsBackground屬性設置,,但是這個屬性與線程的優(yōu)先級是沒有關聯(lián)的。前臺線程只要有一個在運行應用程序就在運行,,當沒有前臺線程運行后應用程序終止,,也就是在任務管理器中的程序一欄中沒有了此程序,但是此時后臺線程任然運行直到其完成操作結(jié)束,,因此在任務管理器的進程一欄中會找到,。

 

[csharp] view plaincopyprint?在CODE上查看代碼片派生到我的代碼片
  1. static void Main(string[] args)
  2. {
  3. Thread.CurrentThread.Name = "main";

  4. Thread t = new Thread(Go);
  5. t.Name = "worker";
  6. t.Start();

  7. Go();
  8. Console.ReadKey();
  9. }
  10. static void Go()
  11. {
  12. Console.WriteLine("from " + Thread.CurrentThread.Name);
  13. Console.WriteLine("background status: " + Thread.CurrentThread.IsBackground.ToString());
  14. }


前臺或主線程明確等待任何后臺線程完成后再結(jié)束才是最好的方式,這大多使用Join方式實現(xiàn),,如果某個工作線程無法實現(xiàn),,可以先終止它,如果失敗再拋棄線程,,從而與進程一起消亡,。

 

線程的優(yōu)先級使用Priority設置或獲取,只有在運行時才有作用,。分為5個級別:

 

[csharp] view plaincopyprint?在CODE上查看代碼片派生到我的代碼片
  1. enum ThreadPriority{Lowest, BelowNormal , Normal, AboveNormal, Highest}

線程優(yōu)先級設置高并不意味著能執(zhí)行實時的工作,,這受限于所屬進程的級別,要執(zhí)行實時的工作需要提示System.Diagnostics命名空間下的Process級別:

 

 

[csharp] view plaincopyprint?在CODE上查看代碼片派生到我的代碼片
  1. using (Process p = Process.GetCurrentProcess())
  2. p.PriorityClass = ProcessPriorityClass.High;

設置為High是一個短暫的最高優(yōu)先級別,,如果設置為Realtime,,那么將讓操作系統(tǒng)不然該進程被其他進程搶占,因此如果此程序一旦出現(xiàn)故障將耗盡操作系統(tǒng)資源,。因此設置為High就是被認為最高和最有用的進程級別了,。

 

對于有用戶界面的程序不適合提升進程級別,因為界面UI的更新需要耗費CPU很多時間,,從而拖慢電腦,。最好的方式是實時工作和用戶界面使用不同的進程,有不同的進程優(yōu)先級,,通過Remoting或者共享內(nèi)存的方式進行進程通信,。

線程執(zhí)行先運行最高優(yōu)先級的線程,,高優(yōu)先級的線程執(zhí)行完之后才開始執(zhí)行低優(yōu)先級的線程。

3,、休眠

Thread.Sleep(int ms); Thread.Sleep(TimeSpan timeout);

上述方法為Thread類的兩個靜態(tài)方法,,用來阻止當前線程指定的時間。

4,、終止

使用Abort和Join兩個方法實現(xiàn),。Join會等待另一個線程執(zhí)行完后再執(zhí)行。而Abort會引發(fā)ThreadAbortException異常,,同時可以傳遞一個終止的參數(shù)信息,。

Thread.Abort();或者Thread.Abort(Object stateInfo)。

5,、異常處理

每個線程都有獨立的執(zhí)行路徑,,因此放在try/catch/finally塊中的新線程都與之無關。補救的方式是在每個線程處理的方法中加入自己的異常處理機制,。

 

[csharp] view plaincopyprint?在CODE上查看代碼片派生到我的代碼片
  1. static void Main(string[] args)
  2. {
  3. try
  4. {
  5. new Thread(Go).Start();
  6. }
  7. catch (Exception ex)
  8. {
  9. Console.Write(ex.Message);
  10. }

  11. Console.ReadKey();
  12. }
  13. static void Go()
  14. {
  15. try
  16. {
  17. throw null;
  18. }catch(Exception e){
  19. Console.Write(e.Message);
  20. }
  21. }

上述處理過程在單獨的線程運行中進行異常處理是可以被捕獲到的,。同時任何線程內(nèi)的未處理的異常都會導致整個程序關閉,對于WPF和WinForm程序中的全局異常僅僅在主界面線程執(zhí)行,,對于工作線程的異常需要手動處理,。有三種情況可以不用處理工作線程的異常:異步委托、BackgroundWroker,、Task Parallel Library,。

 

    本站是提供個人知識管理的網(wǎng)絡存儲空間,所有內(nèi)容均由用戶發(fā)布,,不代表本站觀點,。請注意甄別內(nèi)容中的聯(lián)系方式、誘導購買等信息,,謹防詐騙,。如發(fā)現(xiàn)有害或侵權內(nèi)容,請點擊一鍵舉報,。
    轉(zhuǎn)藏 分享 獻花(0

    0條評論

    發(fā)表

    請遵守用戶 評論公約

    類似文章 更多