日韩性视频-久久久蜜桃-www中文字幕-在线中文字幕av-亚洲欧美一区二区三区四区-撸久久-香蕉视频一区-久久无码精品丰满人妻-国产高潮av-激情福利社-日韩av网址大全-国产精品久久999-日本五十路在线-性欧美在线-久久99精品波多结衣一区-男女午夜免费视频-黑人极品ⅴideos精品欧美棵-人人妻人人澡人人爽精品欧美一区-日韩一区在线看-欧美a级在线免费观看

歡迎訪問 生活随笔!

生活随笔

當(dāng)前位置: 首頁 > 编程语言 > C# >内容正文

C#

【转】C#中的线程 入门

發(fā)布時(shí)間:2025/5/22 C# 184 豆豆
生活随笔 收集整理的這篇文章主要介紹了 【转】C#中的线程 入门 小編覺得挺不錯(cuò)的,現(xiàn)在分享給大家,幫大家做個(gè)參考.

Keywords:C#?線程
Source:http://www.albahari.com/threading/
Author: Joe Albahari
Translator: Swanky Wu
Published:?http://www.cnblogs.com/txw1958/
Download:http://www.albahari.info/threading/threading.pdf

?

?本系列文章可以算是一本很出色的C#線程手冊,思路清晰,要點(diǎn)都有介紹,看了后對C#的線程及同步等有了更深入的理解。

  • 入門
    • 概述與概念
    • 創(chuàng)建和開始使用多線程
  • 線程同步基礎(chǔ)
    • 同步要領(lǐng)
    • 鎖和線程安全
    • Interrupt 和 Abort
    • 線程狀態(tài)
    • 等待句柄
    • 同步環(huán)境
  • 使用多線程
    • 單元模式和Windows Forms
    • BackgroundWorker類
    • ReaderWriterLock類
    • 線程池
    • 異步委托
    • 計(jì)時(shí)器
    • 局部儲(chǔ)存
  • 高級(jí)話題
    • 非阻止同步
    • Wait和Pulse
    • Suspend和Resume
    • 終止線程


一、入門

1. ? ? 概述與概念

?? C#支持通過多線程并行地執(zhí)行代碼,一個(gè)線程有它獨(dú)立的執(zhí)行路徑,能夠與其它的線程同時(shí)地運(yùn)行(單CPU多核)。一個(gè)C#客戶端程序(Console, WPF, or Windows Forms)開始于一個(gè)單線程,這個(gè)單線程是被CLR和操作系統(tǒng)(也稱為“主線程”)自動(dòng)創(chuàng)建的,并可以通過創(chuàng)建額外的線程 組成多線程。這里的一個(gè)簡單的例子及其輸出:

?????除非被指定,否則所有的例子都假定以下命名空間被引用了:??
??
using System;?
?? using System.Threading;

?

class ThreadTest {static void Main() {Thread t = new Thread (WriteY);t.Start(); // Run WriteY on the new thread//同時(shí),主線程做其他事情while (true) Console.Write ("x"); // Write 'x' forever }static void WriteY() {while (true) Console.Write ("y"); // Write 'y' forever } }

主線程創(chuàng)建了一個(gè)新線程“t”,新線程它運(yùn)行了一個(gè)重復(fù)打印字母"y"的方法,同時(shí)主線程重復(fù)打印字母“x”。

線程一旦開始,其 Islive屬性為true,直到線程結(jié)束。當(dāng)委托傳遞給線程的構(gòu)造函數(shù)執(zhí)行完畢線程就結(jié)束一旦結(jié)束,線程不能重新開始。

CLR分配每個(gè)線程到它自己的內(nèi)存堆棧上,來保證局部變量的分離運(yùn)行。

在接下來的例子中,我們定義有一個(gè)局部變量的方法,然后在主線程和新創(chuàng)建的線程上同時(shí)地調(diào)用這個(gè)方法。

static void Main() {new Thread (Go).Start(); // Call Go() on a new threadGo(); // Call Go() on the main thread }static void Go() {// Declare and use a local variable - 'cycles'for (int cycles = 0; cycles < 5; cycles++) Console.Write ('?'); }

?變量cycles的副本分別在各自的內(nèi)存堆棧中創(chuàng)建,輸出也一樣,可預(yù)見,會(huì)有10個(gè)問號(hào)輸出。。

當(dāng)兩個(gè)線程們引用了一些共同的對象實(shí)例的時(shí)候,他們會(huì)共享數(shù)據(jù)。下面是實(shí)例:

class ThreadTest {bool done; static void Main() {ThreadTest tt = new ThreadTest(); // Create a common instance (tt作為他們共同的一個(gè)實(shí)例對象)new Thread (tt.Go).Start(); //新線程調(diào)用tt.Go(); //主線程調(diào)用 }// Note that Go is now an instance method(實(shí)例方法)void Go() {if (!done) { done = true; Console.WriteLine ("Done"); }} } 因?yàn)閮蓚€(gè)線程在同一樣的ThreadTest對象上 調(diào)用了Go(),它們<span style="color:#ff0000;">共享了done字段,這個(gè)結(jié)果輸出的是一個(gè)"Done",而不是兩個(gè)</span>。

靜態(tài)字段提供了另一種在線程間共享數(shù)據(jù)的方式,下面是一個(gè)以done為靜態(tài)字段的例子:

class ThreadTest {static bool done; // Static fields are shared between all threadsstatic void Main() {new Thread (Go).Start();Go();}static void Go() {if (!done) { done = true; Console.WriteLine ("Done"); }} }

上述兩個(gè)例子足以說明, 另一個(gè)關(guān)鍵概念, 那就是線程安全。?輸出實(shí)際上是不確定的:它可能(雖然不大可能) ?"Done" 被打印兩次。然而,如果我們在Go方法里調(diào)換指令的順序, "Done"被打印兩次的機(jī)會(huì)會(huì)大幅地上升:(實(shí)踐證明是的,)

?

static void Go() {if (!done) { Console.WriteLine ("Done"); done = true; } }

?

問題就是一個(gè)線程在判斷if塊的時(shí)候,正好另一個(gè)線程正在執(zhí)行WriteLine語句——在它將done設(shè)置為true之前。

補(bǔ)救措施是當(dāng)讀寫公共字段的時(shí)候,提供一個(gè)互斥;C#提供了lock語句來達(dá)到這個(gè)目的:

class ThreadSafe {static bool done;static readonly object locker = new object();static void Main() {new Thread (Go).Start();Go();}static void Go() {lock (locker) {if (!done) { Console.WriteLine ("Done"); done = true; }}} }

當(dāng)兩個(gè)線程爭奪一個(gè)鎖(互斥鎖)的時(shí)候(在這個(gè)例子里是locker),一個(gè)線程等待,或者說被阻止(blocks), 直到那個(gè)鎖變的可用。在這種情況下,就確保了在同一時(shí)刻只有一個(gè)線程能進(jìn)入臨界區(qū),所以"Done"只被打印了1次(之后done為true)。代碼以如此方式在不確定的多線程環(huán)境中被叫做線程安全


多線程中復(fù)雜而隱蔽錯(cuò)誤的一個(gè)主要原因是數(shù)據(jù)共享。盡管多線程是經(jīng)常必須的,但盡可能保持簡單點(diǎn)。

A thread, while?blocked, doesn't consume CPU resources.(一個(gè)線程,阻塞的時(shí)候,不消耗CPU資源。)

(讓線程等一段時(shí)間再執(zhí)行)


你(主線程)可以等待另一個(gè)線程結(jié)束后再執(zhí)行?通過調(diào)用它(另一線程)的Join方法,例如: static void Main() {Thread t = new Thread (Go);t.Start();t.Join();Console.WriteLine ("Thread t has ended!"); }static void Go() {for (int i = 0; i < 1000; i++) Console.Write ("y"); }

結(jié)果先打印1000次“y”,再打印Thread t has ended!,Join()可設(shè)置等待的時(shí)間,時(shí)間一到,其他線程就會(huì)執(zhí)行


Thread.Sleep?pauses the current thread for a specified period:(阻止當(dāng)前線程一個(gè)指定的時(shí)間)

Thread.Sleep (TimeSpan.FromHours (1)); // sleep for 1 hour Thread.Sleep (500); // sleep for 500 milliseconds

?線程是如何工作的

?? 線程被一個(gè)線程協(xié)調(diào)程序管理著(一個(gè)CLR委托給操作系統(tǒng)的函數(shù))。線程協(xié)調(diào)程序確保將所有活動(dòng)的線程被分配適當(dāng)?shù)膱?zhí)行時(shí)間;并且那些等待或阻止的線程—比如說在互斥鎖中、或在用戶輸入,都是不消耗CPU時(shí)間的。

?? 在單核處理器的電腦中,線程協(xié)調(diào)程序完成一個(gè)時(shí)間片之后迅速地在活動(dòng)的線程之間進(jìn)行切換執(zhí)行。這就導(dǎo)致“波濤洶涌”的行為,例如在第一個(gè)例子,每次重復(fù)的X 或 Y 塊相當(dāng)于分給線程的時(shí)間片。在Windows XP中時(shí)間片通常在10毫秒內(nèi)選擇要比CPU開銷在處理線程切換的時(shí)候的消耗大的多。(即通常在幾微秒?yún)^(qū)間)

?? 在多核的電腦中,多線程被實(shí)現(xiàn)成混合時(shí)間片和真實(shí)的并發(fā)——不同的線程在不同的CPU上運(yùn)行。這幾乎可以肯定仍然會(huì)出現(xiàn)一些時(shí)間切片, 由于操作系統(tǒng)的需要服務(wù)自己的線程,以及一些其他的應(yīng)用程序。

?? 線程由于外部因素(比如時(shí)間片)被中斷被稱為被搶占,在大多數(shù)情況下,一個(gè)線程方面在被搶占的那一時(shí)那一刻就失去了對它的控制權(quán)。

?? 線程 vs. 進(jìn)程

????屬于一個(gè)單一的應(yīng)用程序的所有的線程邏輯上被包含在一個(gè)進(jìn)程中,進(jìn)程指一個(gè)應(yīng)用程序所運(yùn)行的操作系統(tǒng)單元。

??? 線程于進(jìn)程有某些相似的地方:如進(jìn)程并行運(yùn)行在電腦上一樣, 線程并行運(yùn)行在單個(gè)進(jìn)程。進(jìn)程是完全獨(dú)立于彼此的。而線程只是一個(gè)有限程度的隔離。線程與運(yùn)行在相同程序中的其它線程共享(堆heap)內(nèi)存,這就是線程為何如此有用:一個(gè)線程可以在后臺(tái)讀取數(shù)據(jù),而另一個(gè)線程可以在前臺(tái)展現(xiàn)已讀取的數(shù)據(jù)。

??線程的使用和誤用

?多線程有許多用途,下面是最常見的用途:

1、保持一個(gè)快速響應(yīng)的用戶界面

通過在一個(gè)并行的“worker”線程上運(yùn)行耗時(shí)的任務(wù),主UI線程可以自由的繼續(xù)處理鍵盤和鼠標(biāo)事件。

2、有效利用CPU的阻塞

多線程是有用的:當(dāng)一個(gè)線程正在等待一個(gè)另一臺(tái)計(jì)算機(jī)或硬件的響應(yīng)時(shí)當(dāng)一個(gè)線程因?yàn)?span style="text-align:justify;">執(zhí)行任務(wù)而被阻塞時(shí), 其他線程可以利用 計(jì)算機(jī)的未占用資源。

3、并行編程

何時(shí)使用多線程

??? 多線程程序一般被用來在后臺(tái)執(zhí)行耗時(shí)的任務(wù)。主線程保持運(yùn)行,并且工作線程做它的后臺(tái)工作。對于Windows Forms程序來說,如果主線程試圖執(zhí)行冗長的操作,鍵盤和鼠標(biāo)的操作會(huì)變的遲鈍,程序也會(huì)失去響應(yīng)。由于這個(gè)原因,應(yīng)該在工作線程中運(yùn)行一個(gè)耗時(shí)任務(wù)時(shí)添加一個(gè)工作線程,即使在主線程上有一個(gè)友好的提示“處理中...”,以防止工作無法繼續(xù)。這就避免了程序出現(xiàn)由操作系統(tǒng)提示的“沒有相應(yīng)”,來誘使用戶強(qiáng)制結(jié)束程序的進(jìn)程而導(dǎo)致錯(cuò)誤。模式對話框還允許實(shí)現(xiàn)“取消”功能,允許繼續(xù)接收事件,而實(shí)際的任務(wù)已被工作線程完成。BackgroundWorker恰好可以輔助完成這一功能。

?? 在沒有用戶界面的程序里,比如說Windows Service, 多線程在當(dāng)一個(gè)任務(wù)有潛在的耗時(shí),因?yàn)樗诘却砼_(tái)電腦的響應(yīng)(比如一個(gè)應(yīng)用服務(wù)器,數(shù)據(jù)庫服務(wù)器,或者一個(gè)客戶端)的實(shí)現(xiàn)特別有意義。用工作線程完成任務(wù)意味著主線程可以立即做其它的事情

?? 另一個(gè)多線程的用途是在方法中完成一個(gè)復(fù)雜的計(jì)算工作。這個(gè)方法會(huì)在多核的電腦上運(yùn)行的更快,如果工作量被多個(gè)線程分開的話(使用Environment.ProcessorCount屬性來偵測處理芯片的數(shù)量)。

?? 一個(gè)C#程序稱為多線程的可以通過2種方式:

明確地創(chuàng)建和運(yùn)行多線程,或者使用.NET framework的暗中使用了多線程的特性——比如BackgroundWorker類,?線程池,threading timer,遠(yuǎn)程服務(wù)器,或Web Services或ASP.NET程序。

第二種方式,人們別無選擇,必須使用多線程;一個(gè)單線程的ASP.NET web server不是太酷,即使有這樣的事情;幸運(yùn)的是,應(yīng)用服務(wù)器中多線程是相當(dāng)普遍的;唯一值得關(guān)心的是提供適當(dāng)鎖機(jī)制的靜態(tài)變量問題。

? 何時(shí)不要使用多線程

??? 多線程也同樣會(huì)帶來缺點(diǎn),最大的問題是它使程序變的過于復(fù)雜,擁有多線程本身并不復(fù)雜,復(fù)雜是的線程的交互作用,這帶來了無論是否交互是否是有意的,都會(huì)帶來較長的開發(fā)周期,以及帶來間歇性和非重復(fù)性的bugs。因此,要么多線程的交互設(shè)計(jì)簡單一些,要么就根本不使用多線程。除非你有強(qiáng)烈的重寫和調(diào)試欲望。

當(dāng)用戶頻繁地分配和切換線程時(shí),多線程會(huì)帶來增加資源和CPU的開銷。在某些情況下,太多的I/O操作是非常棘手的,當(dāng)只有一個(gè)或兩個(gè)工作線程要比有眾多的線程在相同時(shí)間執(zhí)行任務(wù)塊的多。稍后我們將實(shí)現(xiàn)生產(chǎn)者/耗費(fèi)者 隊(duì)列,它提供了上述功能。

2. ? ?創(chuàng)建和開始使用線程

?? 線程用Thread類來創(chuàng)建,?

一、通過ThreadStart委托來指明方法從哪里開始運(yùn)行,下面是ThreadStart委托如何定義的:【也可以不用】

public?delegate?void?ThreadStart();??

調(diào)用Start方法后,線程開始運(yùn)行,線程一直到它所調(diào)用的方法返回后結(jié)束。下面是一個(gè)例子,使用了C#的語法創(chuàng)建TheadStart委托:

class ThreadTest {static void Main() {Thread t = new Thread (new ThreadStart (Go));t.Start(); // Run Go() on the new thread.Go(); // Simultaneously run Go() in the main thread. }static void Go() { Console.WriteLine ("hello!"); }

在這個(gè)例子中,線程t執(zhí)行Go()方法,大約與此同時(shí)主線程也調(diào)用了Go(),結(jié)果是兩個(gè)幾乎同時(shí)hello被打印出來:

二、一個(gè)線程可以僅通過指定一個(gè)方法來方便的創(chuàng)建,然后C#指出線程開始的方法(不用明確使用委托也可以,例如前面的例子)

?Thread t = new?Thread (Go);??? // No need to explicitly use ThreadStart

在這種情況,ThreadStart被編譯器自動(dòng)推斷出來,

三、另一個(gè)快捷方式是使用一個(gè)lambda表達(dá)式或匿名方法:

static void Main() {Thread t = new Thread ( () => Console.WriteLine ("Hello!") );t.Start(); } 線程有一個(gè)IsAlive屬性,在調(diào)用Start()之后直到線程結(jié)束之前一直為true。一個(gè)線程一旦結(jié)束便不能重新開始了。

? 將數(shù)據(jù)傳入ThreadStart中

最簡單的方法傳遞參數(shù)到一個(gè)線程:是執(zhí)行一個(gè)lambda表達(dá)式,調(diào)用該方法所需的參數(shù)

static void Main() {Thread t = new Thread ( () => Print ("Hello from t!") );t.Start(); }static void Print (string message) {Console.WriteLine (message); }

使用這種方法,您可以將任意數(shù)量的參數(shù)傳遞給方法。你甚至可以把整個(gè)實(shí)現(xiàn)包在一個(gè)多語句λ表達(dá)式中

new Thread (() => {Console.WriteLine ("I'm running on another thread!");Console.WriteLine ("This is so easy!"); }).Start();
使用匿名方法 同樣可以 new Thread (delegate() {... }).Start();

另一種方法是:在Thread’s?Start()方法中傳參數(shù)

static void Main() {Thread t = new Thread (Print);t.Start ("Hello from t!"); }static void Print (object messageObj) {string message = (string) messageObj; // We need to cast here Console.WriteLine (message); } 因?yàn)榫€程的構(gòu)造函數(shù)重載, 接受兩種委托 public delegate void ThreadStart(); public delegate void ParameterizedThreadStart (object obj);

話又說回來,在上面的例子里,我們想更好地區(qū)分開每個(gè)線程的輸出結(jié)果,讓其中一個(gè)線程輸出大寫字母。我們傳入一個(gè)狀態(tài)字到Go中來完成整個(gè)任務(wù),但我們不能使用ThreadStart委托,因?yàn)樗唤邮軈?shù),所幸的是,.NET framework定義了另一個(gè)版本的委托叫做ParameterizedThreadStart, 它可以接收一個(gè)單獨(dú)的object類型參數(shù)(通常需要參數(shù)轉(zhuǎn)換)

Lambda表達(dá)式和捕獲變量:

正如我們所見,一個(gè)lambda表達(dá)式是最強(qiáng)大的方式傳遞數(shù)據(jù)到一個(gè)線程。然而,您必須小心線程開始后變量的意外修改,因?yàn)檫@些變量都是共享的。例如,考慮以下:

for (int i = 0; i < 10; i++)new Thread (() => Console.Write (i)).Start();

輸出是非確定的! ?例如:224458891010 ?(后面的數(shù)不小于前面的數(shù),在1-10之間的數(shù),10次循環(huán)開了10個(gè)線程)

?Here’s a typical result:

The problem is that the?i?variable refers to the?same?memory location throughout the loop’s lifetime(循環(huán)周期時(shí) 兩個(gè)線程捕獲的是同一個(gè)內(nèi)存地址區(qū)). Therefore, each thread calls?Console.Write?on a variable whose value may change as it is running!

?

The solution is to use a temporary variable as follows:

for (int i = 0; i < 10; i++) {int temp = i;new Thread (() => Console.Write (temp)).Start(); } 變量temp位于每個(gè)循環(huán)迭代。因此,每個(gè)線程捕捉不同的內(nèi)存位置(主線程捕獲i的內(nèi)存區(qū),子線程捕獲temp的內(nèi)存區(qū))這樣就沒問題。。(0123456789)

We can illustrate the problem in the earlier code more simply with the following example:

string text = "t1"; Thread t1 = new Thread ( () => Console.WriteLine (text) );text = "t2"; Thread t2 = new Thread ( () => Console.WriteLine (text) );t1.Start(); t2.Start();

Because both lambda expressions capture the same?text?variable,?t2?is printed twice:

t2 t2

? 命名線程

?線程可以通過它的Name屬性進(jìn)行命名,這非常有利于調(diào)試:可以用Console.WriteLine打印出線程的名字,Microsoft Visual Studio可以將線程的名字顯示在調(diào)試工具欄的位置上。線程的名字可以在被任何時(shí)間設(shè)置,但只能設(shè)置一次,重命名會(huì)引發(fā)異常

? 程序的主線程也可以被命名,下面例子里主線程通過CurrentThread屬性命名:

class ThreadNaming {static void Main() {Thread.CurrentThread.Name = "main";Thread worker = new Thread (Go);worker.Name = "worker";worker.Start();Go();}static void Go() {Console.WriteLine ("Hello from " + Thread.CurrentThread.Name);} }

結(jié)果也有可能相反,不能保證哪個(gè)先輸出。線程由操作系統(tǒng)來調(diào)度,每次哪個(gè)線程先運(yùn)行可能不同。


? 前臺(tái)和后臺(tái)線程

?創(chuàng)建的線程默認(rèn)為前臺(tái)線程(而線程池中的線程總是后臺(tái)線程),這意味著任何一個(gè)前臺(tái)線程在運(yùn)行都會(huì)保持程序存活。然而后臺(tái)線程不是。一旦所有的前臺(tái)線程結(jié)束,程序也就結(jié)束了,任何后臺(tái)線程也將突然停止。。

一個(gè)線程的前臺(tái)/后臺(tái)狀態(tài) ?與他的優(yōu)先級(jí)或分配執(zhí)行時(shí)間沒有關(guān)系。。

? 改變線程從前臺(tái)到后臺(tái)不會(huì)以任何方式改變它在CPU協(xié)調(diào)程序中的優(yōu)先級(jí)和狀態(tài)。

?線程的IsBackground屬性控制它的前后臺(tái)狀態(tài),如下實(shí)例:

class PriorityTest {static void Main (string[] args) {Thread worker = new Thread (delegate() { Console.ReadLine(); });if (args.Length > 0) worker.IsBackground = true;worker.Start();} }

? 1、如果程序被調(diào)用的時(shí)候沒有任何參數(shù),工作線程為前臺(tái)線程,并且將等待ReadLine語句來等待用戶按回車來觸發(fā),這期間,主線程退出,但是程序保持運(yùn)行,因?yàn)橐粋€(gè)前臺(tái)線程仍然活著。

? 2、 另一方面如果有參數(shù)傳入Main(),工作線程被賦為后臺(tái)線程,當(dāng)主線程結(jié)束程序立刻退出,終止了ReadLine。后臺(tái)線程終止的這種方式,使任何最后操作都被規(guī)避了,這種方式是不太合適的。好的方式是明確等待任何后臺(tái)工作線程完成后再結(jié)束程序,有兩種方法解決:

? ? ? ? ? ? a、對創(chuàng)建的線程調(diào)用Join()方法,讓其他等待它的結(jié)束

? ? ? ? ? ? b、在線程池中的話,用一個(gè)事件等待來處理

在這兩種情況下,你應(yīng)該指定一個(gè)超時(shí)(timeout),所以可以放棄一個(gè)叛離線程(出于某種原因拒絕完成任務(wù)的線程)。

?? 擁有一個(gè)后臺(tái)工作線程是有益的,最直接的理由是它當(dāng)提到結(jié)束程序它總是可能有最后的發(fā)言權(quán)。

?? 對于程序失敗退出的普遍原因就是存在“被忘記”的前臺(tái)線程。

? 線程優(yōu)先級(jí)

? 線程的Priority 屬性確定了線程相對于其它同一進(jìn)程的活動(dòng)的線程擁有多少執(zhí)行時(shí)間,以下是級(jí)別:

enum?ThreadPriority { Lowest, BelowNormal, Normal, AboveNormal, Highest }

只有多個(gè)線程同時(shí)為活動(dòng)時(shí),優(yōu)先級(jí)才有作用。

注意:提升一個(gè)線程的優(yōu)先級(jí)之前要仔細(xì)想想—它可能導(dǎo)致其他線程的資源缺乏等問題

? 設(shè)置一個(gè)線程的優(yōu)先級(jí)為高一些,并不意味著它能執(zhí)行實(shí)時(shí)的工作,因?yàn)樗芟抻诔绦虻倪M(jìn)程的級(jí)別。要執(zhí)行實(shí)時(shí)的工作,必須提升在System.Diagnostics 命名空間下Process的級(jí)別,像下面這樣:

using (Process p = Process.GetCurrentProcess())p.PriorityClass = ProcessPriorityClass.High;

ProcessPriorityClass.High 實(shí)際上是一個(gè)等級(jí)的最高優(yōu)先級(jí):Realtime(實(shí)時(shí))。設(shè)置進(jìn)程級(jí)別到Realtime通知操作系統(tǒng):你不想讓你的進(jìn)程被搶占了。如果你的程序進(jìn)入一個(gè)偶然的死循環(huán),可以預(yù)期,操作系統(tǒng)被鎖住了,除了關(guān)機(jī)沒有什么可以拯救你了!基于此,High大體上被認(rèn)為最好的選擇實(shí)時(shí)進(jìn)程級(jí)別。

如果一個(gè)實(shí)時(shí)的程序有一個(gè)用戶界面,提升進(jìn)程的級(jí)別是不太好的,因?yàn)楫?dāng)用戶界面UI過于復(fù)雜的時(shí)候,界面的更新耗費(fèi)過多的CPU時(shí)間,拖慢了整臺(tái)電腦。

(雖然在寫這篇文章的時(shí)候,在互聯(lián)網(wǎng)電話程序Skype僥幸地這么做, 也許是因?yàn)樗慕缑嫦喈?dāng)簡單吧。)

?降低主線程的級(jí)別、提升進(jìn)程的級(jí)別、確保實(shí)時(shí)線程不進(jìn)行界面刷新,但這樣并不能避免電腦越來越慢,因?yàn)椴僮飨到y(tǒng)仍會(huì)撥出過多的CPU給整個(gè)進(jìn)程。最理想的方案是使實(shí)時(shí)工作和用戶界面在不同的進(jìn)程(擁有不同的優(yōu)先級(jí))運(yùn)行,通過Remoting或共享內(nèi)存方式進(jìn)行通信,共享內(nèi)存需要Win32 API中的 P/Invoking。(可以搜索看看CreateFileMapping?和?MapViewOfFile)?

? 異常處理

??任何線程創(chuàng)建范圍內(nèi)try/catch/finally塊,當(dāng)線程開始執(zhí)行便不再與其有任何關(guān)系。考慮下面的程序:

public static void Main() {try {new Thread (Go).Start();}catch (Exception ex) {// 不會(huì)在這得到異常Console.WriteLine ("Exception!");}static void Go() { throw null; } } 這里try/catch語句一點(diǎn)用也沒有,新創(chuàng)建的線程將引發(fā)NullReferenceException異常。當(dāng)你考慮到每個(gè)線程有獨(dú)立的執(zhí)行路徑的時(shí)候,便知道這行為是有道理的,

補(bǔ)救方法是在線程處理的方法內(nèi)加入他們自己的異常處理:

public static void Main() {new Thread (Go).Start(); }static void Go() {try {...throw null; // 這個(gè)異常在下面會(huì)被捕捉到 ...}catch (Exception ex) {記錄異常日志,并且或通知另一個(gè)線程我們發(fā)生錯(cuò)誤...}

?? 從.NET 2.0開始,任何線程內(nèi)的未處理的異常都將導(dǎo)致整個(gè)程序關(guān)閉,這意味著忽略異常不再是一個(gè)選項(xiàng)了。因此為了避免由未處理異常引起的程序崩潰,try/catch塊需要出現(xiàn)在每個(gè)線程進(jìn)入的方法內(nèi),至少要在產(chǎn)品程序中應(yīng)該如此

?

轉(zhuǎn)載于:https://www.cnblogs.com/peterYong/p/6556745.html

《新程序員》:云原生和全面數(shù)字化實(shí)踐50位技術(shù)專家共同創(chuàng)作,文字、視頻、音頻交互閱讀

總結(jié)

以上是生活随笔為你收集整理的【转】C#中的线程 入门的全部內(nèi)容,希望文章能夠幫你解決所遇到的問題。

如果覺得生活随笔網(wǎng)站內(nèi)容還不錯(cuò),歡迎將生活随笔推薦給好友。