.Net下的多線程編程

來源:互聯網
上載者:User
 

淺析.Net下的多線程編程多線程是許多作業系統所具有的特性,它能大大提高程式的運行效率,所以多線程編程技術為編程者廣泛關注。目前微軟的.Net戰略正進一步推進,各種相關的技術正為廣大編程者所接受,同樣在.Net中多線程編程技術具有相當重要的地位。本文我就向大家介紹在.Net下進行多線程編程的基本方法和步驟。         開始新線程           在.Net下建立一個新線程是非常容易的,你可以通過以下的語句來開始一個新的線程:         Thread thread = new Thread (new ThreadStart (ThreadFunc));      thread.Start ();           第一條語句建立一個新的Thread對象,並指明了一個該線程的方法。當新的線程開始時,該方法也就被調用執行了。該線程對象通過一個System..Threading.ThreadStart類的一個執行個體以型別安全的方法來調用它要調用的線程方法。        第二條語句正式開始該新線程,一旦方法Start()被調用,該線程就保持在一個"alive"的狀態下了,你可以通過讀取它的IsAlive屬性來判斷它是否處於"alive"狀態。下面的語句顯示了如果一個線程處於"alive"狀態下就將該線程掛起的方法:         if (thread.IsAlive) {      thread.Suspend ();      }           不過請注意,線程對象的Start()方法只是啟動了該線程,而並不保證其線程方法ThreadFunc()能立即得到執行。它只是保證該線程對象能被分配到CPU時間,而實際的執行還要由作業系統根據處理器時間來決定。        一個線程的方法不包含任何參數,同時也不返回任何值。它的命名規則和一般函數的命名規則相同。它既可以是靜態(static)也可以是非靜態(nonstatic)。當它執行完畢後,相應的線程也就結束了,其線程對象的IsAlive屬性也就被置為false了。下面是一個線程方法的執行個體:         public static void ThreadFunc()      {      for (int i = 0; i <10; i++) {      Console.WriteLine("ThreadFunc {0}", i);      }      }              前台線程和後台線程            .Net的公用語言運行時(Common Language Runtime,CLR)能區分兩種不同類型的線程:前台線程和後台線程。這兩者的區別就是:應用程式必須運行完所有的前台線程才可以退出;而對於後台線程,應用程式則可以不考慮其是否已經運行完畢而直接退出,所有的後台線程在應用程式退出時都會自動結束。        一個線程是前台線程還是後台線程可由它的IsBackground屬性來決定。這個屬性是可讀又可寫的。它的預設值為false,即意味著一個線程預設為前台線程。我們可以將它的IsBackground屬性設定為true,從而使之成為一個後台線程。        下面的例子是一個控制台程式,程式一開始便啟動了10個線程,每個線程運行5秒鐘時間。由於線程的IsBackground屬性預設為false,即它們都是前台線程,所以儘管程式的主線程很快就運行結束了,但程式要到所有已啟動的線程都運行完畢才會結束。範例程式碼如下:         using System;      using System.Threading;      class MyApp      {      public static void Main ()      {      for (int i=0; i<10; i++) {      Thread thread = new Thread (new ThreadStart (ThreadFunc));      thread.Start ();      }      }      private static void ThreadFunc ()      {      DateTime start = DateTime.Now;      while ((DateTime.Now - start).Seconds <5)      ;      }      }           接下來我們對上面的代碼進行略微修改,將每個線程的IsBackground屬性都設定為true,則每個線程都是後台線程了。那麼只要程式的主線程結束了,整個程式也就結束了。範例程式碼如下:         using System;      using System.Threading;      class MyApp      {      public static void Main ()      {      for (int i=0; i<10; i++) {      Thread thread = new Thread (new ThreadStart (ThreadFunc));      thread.IsBackground = true;      thread.Start ();      }      }      private static void ThreadFunc ()      {      DateTime start = DateTime.Now;      while ((DateTime.Now - start).Seconds <5)      ;      }      }           既然前台線程和後台線程有這種差別,那麼我們怎麼知道該如何設定一個線程的IsBackground屬性呢?下面是一些基本的原則:對於一些在後台啟動並執行線程,當程式結束時這些線程沒有必要繼續運行了,那麼這些線程就應該設定為後台線程。比如一個程式啟動了一個進行大量運算的線程,可是只要程式一旦結束,那個線程就失去了繼續存在的意義,那麼那個線程就該是作為後台線程的。而對於一些服務於使用者介面的線程往往是要設定為前台線程的,因為即使程式的主線程結束了,其他的使用者介面的線程很可能要繼續存在來顯示相關的資訊,所以不能立即終止它們。這裡我只是給出了一些原則,具體到實際的運用往往需要編程者的進一步仔細斟酌。        線程優先順序           一旦一個線程開始運行,線程發送器就可以控制其所獲得的CPU時間。如果一個託管的應用程式運行在Windows機器上,則線程發送器是由Windows所提供的。在其他的平台上,線程發送器可能是作業系統的一部分,也自然可能是.Net架構的一部分。不過我們這裡不必考慮線程的發送器是如何產生的,我們只要知道通過設定線程的優先順序我們就可以使該線程獲得不同的CPU時間。        線程的優先順序是由Thread.Priority屬性控制的,其值包含:ThreadPriority.Highest、ThreadPriority.AboveNormal、ThreadPriority.Normal、ThreadPriority.BelowNormal和ThreadPriority.Lowest。從它們的名稱上我們自然可以知道它們的優先程度,所以這裡就不多作介紹了。        線程的預設優先順序為ThreadPriority.Normal。理論上,具有相同優先順序的線程會獲得相同的CPU時間,不過在實際執行時,訊息佇列中的線程阻塞或是作業系統的優先順序的提高等原因會導致具有相同優先順序的線程會獲得不同的CPU時間。不過從總體上來考慮仍可以忽略這種差異。你可以通過以下的方法來改變一個線程的優先順序。         thread.Priority = ThreadPriority.AboveNormal;           或是:         thread.Priority = ThreadPriority.BelowNormal;           通過上面的第一句語句你可以提高一個線程的優先順序,那麼該線程就會相應的獲得更多的CPU時間;通過第二句語句你便降低了那個線程的優先順序,於是它就會被分配到比原來少的CPU時間了。你可以在一個線程開始運行前或是在它的運行過程中的任何時候改變它的優先順序。理論上你還可以任意的設定每個線程的優先順序,不過一個優先順序過高的線程往往會影響到其他線程的運行,甚至影響到其他程式的運行,所以最好不要隨意的設定線程的優先順序。           掛起線程和重新開始線程            Thread類分別提供了兩個方法來掛起線程和重新開始線程,也就是Thread.Suspend能暫停一個正在啟動並執行線程,而Thread.Resume又能讓那個線程繼續運行。不像Windows核心,.Net架構是不記錄線程的掛起次數的,所以不管你掛起線程過幾次,只要一次調用Thread.Resume就可以讓掛起的線程重新開始運行。         Thread類還提供了一個靜態Thread.Sleep方法,它能使一個線程自動的掛起一定的時間,然後自動的重新開始。一個線程能在它自身內部調用Thread.Sleep方法,也能在自身內部調用Thread.Suspend方法,可是一定要別的線程來調用它的Thread.Resume方法才可以重新開始。這一點是不是很容易想通的啊?下面的例子顯示了如何運用Thread.Sleep方法:         while (ContinueDrawing) {      DrawNextSlide ();      Thread.Sleep (5000);      }              終止線程           在託管的代碼中,你可以通過以下的語句在一個線程中將另一個線程終止掉:         thread.Abort ();           下面我們來解釋一下Abort()方法是如何工作的。因為公用語言運行時管理了所有的託管的線程,同樣它能在每個線程內拋出異常。Abort()方法能在目標線程中拋出一個ThreadAbortException異常從而導致目標線程的終止。不過Abort()方法被調用後,目標線程可能並不是馬上就終止了。因為只要目標線程正在調用非託管的代碼而且還沒有返回的話,該線程就不會立即終止。而如果目標線程在調用非託管的代碼而且陷入了一個死迴圈的話,該目標線程就根本不會終止。不過這種情況只是一些特例,更多的情況是目標線程在調用託管的代碼,一旦Abort()被調用那麼該線程就立即終止了。        在實際應用中,一個線程終止了另一個線程,不過往往要等那個線程完全終止了它才可以繼續運行,這樣的話我們就應該用到它的Join()方法。範例程式碼如下:         thread.Abort (); // 要求終止另一個線程      thread.Join (); // 只到另一個線程完全終止了,它才繼續運行           但是如果另一個線程一直不能終止的話(原因如前所述),我們就需要給Join()方法設定一個時間限制,方法如下:         thread.Join (5000); // 暫停5秒           這樣,在5秒後,不管那個線程有沒有完全終止,本線程就強行運行了。該方法還返回一個布爾型的值,如果是true則表明那個線程已經完全終止了,而如果是false的話,則表明已經超過了時間限制了。        時鐘線程            .Net架構中的Timer類可以讓你使用時鐘線程,它是包含在System.Threading名字空間中的,它的作用就是在一定的時間間隔後調用一個線程的方法。下面我給大家展示一個具體的執行個體,該執行個體以1秒為時間間隔,在控制台中輸出不同的字串,代碼如下:         using System;      using System.Threading;      class MyApp      {      private static bool TickNext = true;      public static void Main ()      {      Console.WriteLine ("Press Enter to terminate...");      TimerCallback callback = new TimerCallback (TickTock);      Timer timer = new Timer (callback, null, 1000, 1000);      Console.ReadLine ();      }      private static void TickTock (object state)      {      Console.WriteLine (TickNext ? "Tick" : "Tock");      TickNext = ! TickNext;      }      }           從上面的代碼中,我們知道第一個函數回調是在1000毫秒後才發生的,以後的函數回調也是在每隔1000毫秒之後發生的,這是由Timer對象的建構函式中的第三個參數所決定的。程式會在1000毫秒的時間間隔後不斷的產生新線程,只到使用者輸入斷行符號才結束運行。不過值得注意的是,雖然我們設定了時間間隔為1000毫秒,但是實際啟動並執行時候往往並不能非常精確。因為Windows作業系統並不是一個即時系統,而公用語言運行時也不是即時的,所以由於線程調度的千變萬化,實際的運行效果往往是不能精確到毫秒級的,但是對於一般的應用來說那已經是足夠的了,所以你也不必十分苛求。           小結           本文介紹了在.Net下進行多線程編程所需要掌握的一些基本知識。從文章中我們可以知道在.Net下進行多線程編程相對以前是有了大大的簡化,但是其功能並沒有被削弱。使用以上的一些基本知識,讀者就可以試著編寫.Net下的多線程程式了。不過要編寫出功能更加強大而且Bug少的多線程應用程式,讀者需要掌握諸如線程同步、線程池等進階的多線程編程技術。讀者不妨參考一些作業系統方面或是多線程編程方面的技術叢書。

聯繫我們

該頁面正文內容均來源於網絡整理,並不代表阿里雲官方的觀點,該頁面所提到的產品和服務也與阿里云無關,如果該頁面內容對您造成了困擾,歡迎寫郵件給我們,收到郵件我們將在5個工作日內處理。

如果您發現本社區中有涉嫌抄襲的內容,歡迎發送郵件至: info-contact@alibabacloud.com 進行舉報並提供相關證據,工作人員會在 5 個工作天內聯絡您,一經查實,本站將立刻刪除涉嫌侵權內容。

A Free Trial That Lets You Build Big!

Start building with 50+ products and up to 12 months usage for Elastic Compute Service

  • Sales Support

    1 on 1 presale consultation

  • After-Sales Support

    24/7 Technical Support 6 Free Tickets per Quarter Faster Response

  • Alibaba Cloud offers highly flexible support services tailored to meet your exact needs.