国产探花免费观看_亚洲丰满少妇自慰呻吟_97日韩有码在线_资源在线日韩欧美_一区二区精品毛片,辰东完美世界有声小说,欢乐颂第一季,yy玄幻小说排行榜完本

首頁 > 學院 > 開發(fā)設計 > 正文

C#多線程(一)

2019-11-17 03:15:53
字體:
來源:轉載
供稿:網(wǎng)友

C#多線程(一)

2014-03-27 16:49 by OshynSong, ... 閱讀, ... 評論, 收藏, 編輯

一、定義與理解

1、定義

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

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

線程被一個CLR委托給操作系統(tǒng)的進程協(xié)調函數(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上查看代碼片staticvoidMain(string[]args)
  • {
  • Threadt=newThread(Write);
  • t.Start();
  • Write();
  • Console.ReadKey();
  • }
  • staticvoidWrite()
  • {
  • for(inti=0;i<5;i++)
  • Console.Write("@");
  • }

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

    [csharp]view plaincopyprint?在CODE上查看代碼片staticbooldone;
  • staticvoidMain(string[]args)
  • {
  • Threadt=newThread(Write);
  • t.Start();
  • Write();
  • Console.ReadKey();
  • }
  • staticvoidWrite()
  • {
  • if(!done)
  • {
  • done=true;
  • Console.Write("@");
  • }
  • }

    這里輸出的只有一個字符,但是很可能在極少數(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)建出新的線程,然后調用Start方法使得線程進入就緒狀態(tài),得到系統(tǒng)資源后就執(zhí)行,在執(zhí)行過程中可能有等待、休眠、死亡和阻塞四種狀態(tài)。正常執(zhí)行結束時間片后返回到就緒狀態(tài)。如果調用Suspend方法會進入等待狀態(tài),調用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調用此方法的線程引發(fā)ThreadAbortException終止線程
    Join阻止調用線程,知道某個線程終止時為止
    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上查看代碼片publicdelegatevoidThreadStart();
  • publicdelegatevoidParameterizedThreadStart(objectobj);
  • 任何時候C#使用上述兩個委托中的一個自動進行線程的創(chuàng)建。

    [csharp]view%20plaincopyprint?staticvoidMain()
  • {
  • Threadt=newThread(newTheadStart(Go));
  • t.Start();
  • Go();
  • }
  • staticvoidGo()
  • {
  • Console.Write("hello!");
  • }
  • 上述方式不傳遞參數(shù),可以使用new%20Thead(Go)的方式直接創(chuàng)建,此時C#會在編譯時自動匹配使用的是ThreadStart委托創(chuàng)建的。下面可以進行傳遞參數(shù)創(chuàng)建線程。

    [csharp]view%20plaincopyprint?staticvoidMain()
  • {
  • Threadt=newThread(Go);
  • t.Start("hello");
  • Go();
  • }
  • staticvoidGo(objectmsg)
  • {
  • stringmessage=(string)msg;
  • Console.Write(message);
  • }

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

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

    [csharp]view%20plaincopyprint?newThread(()=>Go("hello"));

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

    [csharp]view%20plaincopyprint?newThread(()=>{
  • Console.Write("helloworld!");
  • ......
  • }).Start();
  • 注意問題:使用Lambda表達式的時候會存在變量捕獲的問題,如果捕獲的變量是共享的,會出現(xiàn)線程不安全的問題。看下面的例子:

    [csharp]view%20plaincopyprint?staticvoidMain(string[]args)
  • {
  • for(inti=0;i<10;i++)
  • newThread(()=>Write(i)).Start();
  • Console.ReadKey();
  • }
  • staticvoidWrite(objectobj)
  • {
  • stringmsg=Convert.ToString(obj);
  • Console.Write(msg);
  • }
  • 上述由于使用Lambda表達式傳遞參數(shù),在for循環(huán)的作用域內(nèi),新建的十個線程共享了局部變量i,傳遞進入i參數(shù)可能被多個線程已經(jīng)修改,因此每次輸出結果都是不確定的,兩次結果如下:

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

    發(fā)表評論 共有條評論
    用戶名: 密碼:
    驗證碼: 匿名發(fā)表
    主站蜘蛛池模板: 怀仁县| 闸北区| 德格县| 河西区| 琼中| 越西县| 锡林郭勒盟| 东阳市| 察雅县| 石林| 兴安盟| 和平县| 丁青县| 惠来县| 茶陵县| 仙游县| 忻州市| 平利县| 阳西县| 孟连| 商河县| 南涧| 永春县| 班玛县| 平潭县| 雷波县| 敦煌市| 尚志市| 新邵县| 昌都县| 江华| 苏尼特左旗| 黎川县| 阳西县| 新密市| 启东市| 介休市| 齐河县| 曲周县| 雅安市| 吉安市|