六月婷婷综合激情-六月婷婷综合-六月婷婷在线观看-六月婷婷在线-亚洲黄色在线网站-亚洲黄色在线观看网站

明輝手游網中心:是一個免費提供流行視頻軟件教程、在線學習分享的學習平臺!

初識C#線程

[摘要]作者: BUIILDER.COM使用多線程技術能有效地幫助你實現應用程序的更高性能和更優良的可伸縮性。但在真正運用這項技術的時候務必小心。本文是對線程技術所牽扯的工具和技術問題系列文章的開篇。我首先對線程概念進行介紹,然后總結一些常用的構造,最后介紹它們的用法。線程的兩面性用Java語言編寫多線程...
作者: BUIILDER.COM

使用多線程技術能有效地幫助你實現應用程序的更高性能和更優良的可伸縮性。但在真正運用這項技術的時候務必小心。本文是對線程技術所牽扯的工具和技術問題系列文章的開篇。我首先對線程概念進行介紹,然后總結一些常用的構造,最后介紹它們的用法。

線程的兩面性

用Java語言編寫多線程程序并不難,這是好事也是壞事。微軟在開發C#時,他們把這種易用性的窘境全盤照搬到了整個新平臺上。同時,C#相比Java具有更多的程序原語,但是Thread對象和同步監視器的基本Java原語從形式和功能上看都已足夠提供強大的線程編程能力了。因此,在決定為應用程序采用多線程技術之前務必小心。

為什么不用多線程
首先得記住,在決定是否采用多線程技術時,除非你正在玩代碼,否則千萬別因為多線程編程夠“酷”而簡單地使用線程技術編程。多線程編程技術太時髦了,如果你不小心點你的老板遲早也會著迷,那時你就死定了。其次,不要因為讓程序運行得更快而輕易采用多線程,除非你真的能證明單線程實現確實慢得可以。最后,在冒昧地一頭扎進多線程機制之前,先回憶下微軟所提供的一種公寓(apartment)模型,也就是把對象寫成單線程構造而運行在多線程環境下。所以,說來說去,你并不一定非要采用多線程編碼。不過,公寓模型是另外一個話題了。

如果做得不對,多線程編程勢必會打開“潘朵拉的盒子”(意思是說惹出無數的麻煩)。重復性不明顯、產生程序垃圾、記數器沒有正確增值等等。你的應用程序還可能突然掛起。例如,數據庫連接這類資源就可能出人意料地關閉或者變得過載。高級開發人員所面臨的一個大麻煩就是解決線程問題。這些大問題不花點時間休想解決,而且它們對產品交貨日期以及產品可靠性產生了嚴重的負面影響。

為什么要用多線程
如果你的應用程序需要采取以下的操作,那么你盡可在編程的時候考慮多線程機制:

連續的操作,需要花費忍無可忍的過長時間才可能完成
并行計算
為了等待網絡、文件系統、用戶或其他I/O響應而耗費大量的執行時間
所以說,在動手之前,先保證自己的應用程序中是否出現了以上3種情形。

如果你的代碼運行得足夠快,但是你認為你能讓它運行得更快(假設你確實有這本事),我勸你最好不要接受這種誘惑。如果你不能肯定程序的計算操作并行性(例如針對同一數據表的并發數據庫更改——當你的數據庫達到了數據表級鎖定的情況下),那么再想想其他法子吧。還有,如果你不知道應用程序是否因為等待輸入或輸出而花費了過多的時間,那么請首先搞清楚真正耗費時間的情況再說。實際上,啟動3個線程以百萬分之一的步長計算圓周率所消耗的時間就比同一線程重復計算3次要長得多。為什么會出現這種失敗的情形呢?原因就在于,雖然第2條并行計算確實可用,但設計者卻恰恰忽略了以上第3個標準:并行計算可以用到的一次計算期間卻沒有空閑周期。

假如你在為一臺裝備了多個處理器的并行計算機編寫程序,則以上規則在這種情況下例外,你可以通過適當的并行操作設計而令軟件性能大大獲益——哪怕每一操作都對CPU時間極其貪婪。

基本的線程管理工具
剛才我已經為多線程編程提出了相當程度的警告,同時還為何時使用或者不使用多線程提出了建議,接下來我對多線程編程所能利用的某些工具進行闡述。

Thread對象

.NET庫提供了一種名為System.Threading.Thread的對象,這種對象代表了單一線程。你可以啟動線程、在當前線程繼續運行的情況下設法完成線程的任務。這對那些需要打印文檔或者保存大型文件但希望獲得用戶確認請求并給用戶返回控制的應用程序來說幫助實在太大了。我們通過程序清單A演示了這一機制。

程序清單A


using System;
using System.Threading;
namespace Threads1 {
class Listing1 {
static void SayHello() { 
 Console.WriteLine("Hello, ");
 Thread.Sleep(750 /*mSec */);
 Console.WriteLine("World");
 }
static void Main(string[] args) {
Thread t1 = new Thread(new ThreadStartSayHello));
t1.Start();
Console.WriteLine("Thread started. Main done.");
}
 }
}




我們首先創建了一種方法:SayHello,由它完成我們的任務——顯示問候語。它的簽名必須匹配 System.Threading.ThreadStart指派(delegate)。注意,SayHello 方法調用了Thread.Sleep(int numMillisecs)方法。這是一種相當有用的構造而且會經常出現在這類示例中。

在主程序中,我們通過帶SayHello方法的ThreadStart指派創建了一個新線程,并在該線程上調用Start方法。我們創建的線程隨之被啟動,然后我們的主線程在這個例子中繼續運行到結束。

在很多情況下你可能要在各個線程中分別執行存在輕微差別的任務,同時需要把某種參數從一種任務所在的線程傳遞給另一任務所在的線程。要完成這一目標可以采取好幾種合理的方式,最直接的做法就是創建一種Task對象,由它保存線程、特有的參數以及提供ThreadStart指派的worker方法。利用worker方法即可讀取所提供的參數,因為它正好就是Task對象的成員所以對線程當然是唯一的。通過令線程成為一種公共字段,你就可以獲得訪問線程所有成員的權限而不必編寫額外的封裝代碼了。請參看程序清單B 閱讀這一技術的有關示例。

程序清單B
using System;
using System.Threading;
namespace TaskDemo {
 public class MyTask {
public Thread m_thread;
string m_name;
public MyTask(string name) {
m_name = name;
m_thread = new Thread(new ThreadStart(Worker));
 }
private void Worker() {
Console.WriteLine("Hello, ");
 Thread.Sleep(1500);
Console.WriteLine(m_name);
}
 } 
class TaskDemo1 {
 static void Main(string [] args){ 
 MyTask task1 = new MyTask("Bill");
 MyTask task2 = new MyTask("Steve");
 task1.m_thread.Start();
 task2.m_thread.Start();
 }
}
}




你甚至可以通過在保存線程的任務中定義字段的方法提供Task對象的某種返回值,在線程完成前設置這一返回值,最后在這項任務完成以后從啟動這項任務的線程讀取它。

你可以暫停一個線程、等待其他線程完成其任務。你可以在打算采集返回結果的時候執行兩種操作,在三個分隔的線程之間執行數據庫更新但直到所有線程都結束時才想進行數據處理也可以采用以上兩種操作。該技術如程序清單C所示。

程序清單C:
http://builder.com.com/utils/sidebar.jhtml?id=u00220020531pcb01.htm&index=3


這里,我們采用了程序清單A的代碼創建程序。這次我們運行兩個線程,每一個線程完成同以前一樣的任務。調用兩個線程的Start () 方法之后調用它們的Join()方法。對線程調用Join()方法會令調用線程暫停執行直到被調用線程結束。因此thread1.Start ()方法會令主線程暫停直到thread1完成。然后我們對thread2執行同樣的操作。結果,主線程直到thread1和 thread2都完成了才最后完成。

這個例子的思想分為兩部分。首先,某一個線程不能調用另一線程上的Join方法除非后者已經啟動。第二,有多于兩種形式的Join可以設定調用線程繼續運行的超時時間哪怕被調用線程仍在運行。

計算機科學中經常會提到看門狗概念,所謂看門狗(watchdog)其實就是負責保證功能正確性或者處理不正確功能的實體。另一種實體,也就是常用的看門狗計時器(watchdog timer)則通常負責保證另一任務在合理的時間內按時完成。程序清單D所示就是實現看門狗計時器的簡單實現機制。

程序清單D:
http://builder.com.com/utils/sidebar.jhtml?id=u00220020531pcb01.htm&index=4

thread1啟動之后我們就加入該線程但提供了10秒鐘的超時時間。因為thread1內置15秒暫停設置,所以在加入超期之后還會繼續存活。主線程則測試thread1.IsAlive,如果它還活動則終止線程。

同步和監視器
同步指的是保證一次一節代碼中只有一個線程在執行的措施。討論同步技術已經超出了本文所涉及的主題范圍,但單個線程模塊之內為可靠起見實際上會產生為數不少的構造。然而,它們中的大多數在這些代碼塊的外部,在大多數時間內都工作很正常,這樣,我們一直所熟知的“如果編譯通過并且得到我期望的答案那么它就是正確的”這種說法在這里就不一定成立了。這就是多線程為什么如此危險的部分原因。

監視器是最基礎的同步構造。任何對象都有自己關聯的監視器,一個監視器只能分配給一個對象。監視器上有一個“鎖(lock)”,這個鎖可以在某一時刻被唯一線程獲得。在另一線程可以獲得這把鎖之前必須先釋放它。你可以聲明某個對象對所有線程可見來保護某一段代碼,比如類字段等。你還可以在實施某種操作之前讓某段代碼從監視器那里獲得對象鎖,然后在操作完成之后釋放這把鎖。該構造的示范如程序清單E所示。

程序清單E:
http://builder.com.com/utils/sidebar.jhtml?id=u00220020531pcb01.htm&index=5

這里我們聲明了一個對象myLockObject,該對象的唯一目的就是提供同步監視器。在 SayHello方法中,無論何時只要需要我們就允許兩個線程打印出“Hello”的字樣。然而,現在我們就通過myMonitorObject所關聯的監視器控制了“Wonderful”和“World”的打印,這樣,一個線程在被允許開始打印之前另一線程必須完成兩次打印。

實現以上機制還可以采用另兩種技術——lock()關鍵詞何MethodImplAttribute屬性。示例請參看程序清單F。

程序清單F:
http://builder.com.com/utils/sidebar.jhtml?id=u00220020531pcb01.htm&index=6

我們用lock(…){ … }代替Monitor.Enter(…) and Monitor.Exit(…)構造。這些構造在效果上是相同的,只不過后者相比前者更為便捷些。我們還增加了一個方法SayHello2 (),它具有屬性MethodImpl。這一屬性指定了將被同步的全部方法。實質等價于在包含這些同步方法的類型對象被允許調用方法之前強迫調用代碼獲取類型對象關聯的監視器上的鎖。這比在lock(){…}語句中封裝方法代碼可清楚多了。注意,文檔中定義該屬性為MethodImplAttribute,但它的實現卻叫做MethodImpl。根據聲明屬性的陳述習慣,也許微軟的某個開發人員自己可能沒注意到這一疏忽。

小結
這篇文章的內容涵蓋很多方面的問題。我已經討論了采用或者不采用多線程技術的若干理由,同時還展示了某些用在多線程編程中的原語構造。此外我還介紹了線程對象并解釋了運行若干線程完成任務的原理、什么是監視器以及如何通過監視器的使用完成代碼的同步。在特定的情況下,lock關鍵詞和MethodImpl屬性完成同樣的工作。

在后續的文章里我將繼續描述其它基本構造,實現一個線程池,并且探討更多的構造類型, 例如線程本地存儲和重疊I/O等。






標簽:初識C#線程 

相關文章

主站蜘蛛池模板: 婷婷开心激情网 | 日韩欧美综合在线二区三区 | 日韩精品成人 | 欧美丝袜一区二区三区 | 在线看亚洲 | 香蕉视频你懂的 | 欧美一级黄色录相 | 日韩亚洲国产综合久久久 | 中文字幕欧美日韩久久 | 亚洲欧美国产人成在线app | 色妞综合网 | 日产乱码卡一卡2卡三卡四福利 | 四虎国产精品一区二区 | 亚洲视频综合 | 亚洲精品在线看 | 亚洲视频播放 | 天天操天天看 | 亚洲欧美日本视频 | 亚洲国产2017男人a天堂 | 亚洲成a人片在线观看播放 亚洲成a人片在线观看www | 天天色综 | 日韩诱惑 | 日本国产欧美色综合 | 日韩大片免费观看 | 亚洲伊人久久大香线蕉结合 | 青青青爽视频在线观看 | 日韩精品资源 | 三级aa| 色干网| 日韩免费精品视频 | 欧美一级成人一区二区三区 | 日本国产一区二区三区 | 手机看片日韩日韩国产在线看 | 亚洲国产精品久久 | 日本免费观看日本高清视频 | 婷婷六月色 | 中文字幕35 | 手机看片福利日韩国产 | 日日噜噜夜夜狠狠久久aⅴ 日日噜噜夜夜狠狠扒开双腿 | 色呦呦在线观看视频 | 日韩3级|