C#多線程2

2.2 線程的常用屬性
2.2.1 線程的標(biāo)識(shí)符 ManagedThreadId是確認(rèn)線程的唯一標(biāo)識(shí)符,程序在大部分情況下都是通過Thread.ManagedThreadId來辨別線程的。而Name是一個(gè)可變值,在默認(rèn)時(shí)候,Name為一個(gè)空值 Null,開發(fā)人員可以通過程序設(shè)置線程的名稱,但這只是一個(gè)輔助功能。 2.2.2 線程的優(yōu)先級別 當(dāng)線程之間爭奪CPU時(shí)間時(shí),CPU按照線程的優(yōu)先級給予服務(wù)。高優(yōu)先級的線程可以完全阻止低優(yōu)先級的線程執(zhí)行。.NET為線程設(shè)置了Priority屬性來定義線程執(zhí)行的優(yōu)先級別,里面包含5個(gè)選項(xiàng),其中Normal是默認(rèn)值。除非系統(tǒng)有特殊要求,否則不應(yīng)該隨便設(shè)置線程的優(yōu)先級別。
2.2.3 線程的狀態(tài) 通過ThreadState可以檢測線程是處于Unstarted、Sleeping、Running 等等狀態(tài),它比 IsAlive 屬性能提供更多的特定信息。 前面說過,一個(gè)應(yīng)用程序域中可能包括多個(gè)上下文,而通過CurrentContext可以獲取線程當(dāng)前的上下文。 CurrentThread是最常用的一個(gè)屬性,它是用于獲取當(dāng)前運(yùn)行的線程。 2.2.4 System.Threading.Thread的方法 Thread 中包括了多個(gè)方法來控制線程的創(chuàng)建、掛起、停止、銷毀,以后來的例子中會(huì)經(jīng)常使用。

線城示例:

運(yùn)行結(jié)果:

2.3 前臺(tái)線程和后臺(tái)線程 前臺(tái)線程:只有所有的前臺(tái)線程都結(jié)束,應(yīng)用程序才能結(jié)束。默認(rèn)情況下創(chuàng)建的線程 ? ? ? ? ? ? ?都是前臺(tái)線程 后臺(tái)線程:只要所有的前臺(tái)線程結(jié)束,后臺(tái)線程自動(dòng)結(jié)束。通過Thread.IsBackground設(shè)置后臺(tái)線程。必須在調(diào)用Start方法之前設(shè)置線程的類型,否則一旦線程運(yùn)行,將無法改變其類型。 通過BeginXXX方法運(yùn)行的線程都是后臺(tái)線程。


運(yùn)行結(jié)果:前臺(tái)線程執(zhí)行完,后臺(tái)線程未執(zhí)行完,程序自動(dòng)結(jié)束。

把bThread.IsBackground = true注釋掉,運(yùn)行結(jié)果:主線程執(zhí)行完畢后(Main函數(shù)),程序并未結(jié)束,而是要等所有的前臺(tái)線程結(jié)束以后才會(huì)結(jié)束。

后臺(tái)線程一般用于處理不重要的事情,應(yīng)用程序結(jié)束時(shí),后臺(tái)線程是否執(zhí)行完成對整個(gè)應(yīng)用程序沒有影響。如果要執(zhí)行的事情很重要,需要將線程設(shè)置為前臺(tái)線程。 2.4 線程同步 所謂同步:是指在某一時(shí)刻只有一個(gè)線程可以訪問變量。 如果不能確保對變量的訪問是同步的,就會(huì)產(chǎn)生錯(cuò)誤。 c#為同步訪問變量提供了一個(gè)非常簡單的方式,即使用c#語言的關(guān)鍵字Lock,它可以把一段代碼定義為互斥段,互斥段在一個(gè)時(shí)刻內(nèi)只允許一個(gè)線程進(jìn)入執(zhí)行,而其他線程必須等待。在c#中,關(guān)鍵字Lock定義如下: Lock(expression) { ? statement_block } expression代表你希望跟蹤的對象: ? ? ? ? ? 如果你想保護(hù)一個(gè)類的實(shí)例,一般地,你可以使用this; ? ? ? ? ? 如果你想保護(hù)一個(gè)靜態(tài)變量(如互斥代碼段在一個(gè)靜態(tài)方法內(nèi)部),一般使用類名就可以了 而statement_block就算互斥段的代碼,這段代碼在一個(gè)時(shí)刻內(nèi)只可能被一個(gè)線程執(zhí)行。 以書店賣書為例
運(yùn)行結(jié)果:
從運(yùn)行結(jié)果可以看出,兩個(gè)線程同步訪問共享資源,沒有考慮同步的問題,結(jié)果不正確。 考慮線程同步,改進(jìn)后的代碼:
運(yùn)行結(jié)果:
2.5 跨線程訪問
點(diǎn)擊“測試”,創(chuàng)建一個(gè)線程,從0循環(huán)到10000給文本框賦值,代碼如下:

運(yùn)行結(jié)果:

產(chǎn)生錯(cuò)誤的原因:textBox1是由主線程創(chuàng)建的,thread線程是另外創(chuàng)建的一個(gè)線程,在.NET上執(zhí)行的是托管代碼,C#強(qiáng)制要求這些代碼必須是線程安全的,即不允許跨線程訪問Windows窗體的控件。 解決方案: 1、在窗體的加載事件中,將C#內(nèi)置控件(Control)類的CheckForIllegalCrossThreadCalls屬性設(shè)置為false,屏蔽掉C#編譯器對跨線程調(diào)用的檢查。 private void Form1_Load(object sender, EventArgs e) { ? ? ? ?//取消跨線程的訪問 ? ? ? ?Control.CheckForIllegalCrossThreadCalls = false; } 使用上述的方法雖然可以保證程序正常運(yùn)行并實(shí)現(xiàn)應(yīng)用的功能,但是在實(shí)際的軟件開發(fā)中,做如此設(shè)置是不安全的(不符合.NET的安全規(guī)范),在產(chǎn)品軟件的開發(fā)中,此類情況是不允許的。如果要在遵守.NET安全標(biāo)準(zhǔn)的前提下,實(shí)現(xiàn)從一個(gè)線程成功地訪問另一個(gè)線程創(chuàng)建的空間,要使用C#的方法回調(diào)機(jī)制。 2、使用回調(diào)函數(shù) 回調(diào)實(shí)現(xiàn)的一般過程: C#的方法回調(diào)機(jī)制,也是建立在委托基礎(chǔ)上的,下面給出它的典型實(shí)現(xiàn)過程。 (1)、定義、聲明回調(diào)。 1 //定義回調(diào) 2 private delegate void DoSomeCallBack(Type para); 3 //聲明回調(diào) 4 DoSomeCallBack doSomaCallBack; 可以看出,這里定義聲明的“回調(diào)”(doSomaCallBack)其實(shí)就是一個(gè)委托。 (2)、初始化回調(diào)方法。 doSomeCallBack=new DoSomeCallBack(DoSomeMethod); 所謂“初始化回調(diào)方法”實(shí)際上就是實(shí)例化剛剛定義了的委托,這里作為參數(shù)的DoSomeMethod稱為“回調(diào)方法”,它封裝了對另一個(gè)線程中目標(biāo)對象(窗體控件或其他類)的操作代碼。 (3)、觸發(fā)對象動(dòng)作 Opt ?obj.Invoke(doSomeCallBack,arg); 其中Opt obj為目標(biāo)操作對象,在此假設(shè)它是某控件,故調(diào)用其Invoke方法。Invoke方法簽名為: object ?Control.Invoke(Delegate ?method,params ?object[] args); 它的第一個(gè)參數(shù)為委托類型,可見“觸發(fā)對象動(dòng)作”的本質(zhì),就是把委托doSomeCallBack作為參數(shù)傳遞給控件的Invoke方法,這與委托的使用方式是一模一樣的。 最終作用于對象Opt obj的代碼是置于回調(diào)方法體DoSomeMethod()中的,如下所示: private void DoSomeMethod(type para) { ? ? //方法體 ? ?Opt obj.someMethod(para); } 如果不用回調(diào),而是直接在程序中使用“Opt obj.someMethod(para);”,則當(dāng)對象Opt obj不在本線程(跨線程訪問)時(shí)就會(huì)發(fā)生上面所示的錯(cuò)誤。 從以上回調(diào)實(shí)現(xiàn)的一般過程可知:C#的回調(diào)機(jī)制,實(shí)質(zhì)上是委托的一種應(yīng)用。在C#網(wǎng)絡(luò)編程中,回調(diào)的應(yīng)用是非常普遍的,有了方法回調(diào),就可以在.NET上寫出線程安全的代碼了。 使用方法回調(diào),實(shí)現(xiàn)給文本框賦值:


本文轉(zhuǎn)載自博客園:https://www.cnblogs.com/dotnet261010/p/6159984.html