C#實(shí)現(xiàn)多線程編程的簡單案例
一、使用線程的理由
1、可以使用線程將代碼同其他代碼隔離,提高應(yīng)用程序的可靠性。
2、可以使用線程來簡化編碼。
3、可以使用線程來實(shí)現(xiàn)并發(fā)執(zhí)行。
二、基本知識
1、進(jìn)程與線程:進(jìn)程作為操作系統(tǒng)執(zhí)行程序的基本單位,擁有應(yīng)用程序的資源,進(jìn)程包含線程,進(jìn)程的資源被線程共享,線程不擁有資源。
2、前臺線程和后臺線程:通過Thread類新建線程默認(rèn)為前臺線程。當(dāng)所有前臺線程關(guān)閉時,所有的后臺線程也會被直接終止,不會拋出異常。
3、掛起(Suspend)和喚醒(Resume):由于線程的執(zhí)行順序和程序的執(zhí)行情況不可預(yù)知,所以使用掛起和喚醒容易發(fā)生死鎖的情況,在實(shí)際應(yīng)用中應(yīng)該盡量少用。
4、阻塞線程:Join,阻塞調(diào)用線程,直到該線程終止。
5、終止線程:Abort:拋出 ThreadAbortException 異常讓線程終止,終止后的線程不可喚醒。Interrupt:拋出 ThreadInterruptException 異常讓線程終止,通過捕獲異??梢岳^續(xù)執(zhí)行。
6、線程優(yōu)先級:Highest AboveNormal Normal BelowNormal Lowest ,默認(rèn)為Normal。
三、線程的使用
線程函數(shù)通過委托傳遞,可以不帶參數(shù),也可以帶參數(shù)(只能有一個參數(shù)),可以用一個類或結(jié)構(gòu)體封裝參數(shù)。
案例:
class Program { static void Main(string[] args) { Thread t1 = new Thread(new ThreadStart(TestMethod));//創(chuàng)建無參數(shù)數(shù)線程 Thread t2 = new Thread(new ParameterizedThreadStart(TestMethod));//創(chuàng)建帶參數(shù)的線程 //設(shè)置為后臺進(jìn)程 t1.IsBackground = true; t2.IsBackground = true; t1.Start(); t2.Start("hello"); Console.ReadKey(); } public static void TestMethod() { Console.WriteLine("不帶參數(shù)的線程函數(shù)"); } //參數(shù)要定義為object 類型 public static void TestMethod(object data) { string datastr = data as string; Console.WriteLine("帶參數(shù)的線程函數(shù),參數(shù)為:{0}", datastr); } }
四、線程池
由于線程的創(chuàng)建和銷毀需要耗費(fèi)一定的開銷,過多的使用線程會造成內(nèi)存資源的浪費(fèi),出于對性能的考慮,于是引入了線程池的概念。線程池維護(hù)一個請求隊列,線程池的代碼從隊列提取任務(wù),然后委派給線程池的一個線程執(zhí)行,線程執(zhí)行完不會被立即銷毀,這樣既可以在后臺執(zhí)行任務(wù),又可以減少線程創(chuàng)建和銷毀所帶來的開銷。
線程池線程默認(rèn)為后臺線程(IsBackground)。
class Program { static void Main(string[] args) { //將工作項加入到線程池隊列中,這里可以傳遞一個線程參數(shù) ThreadPool.QueueUserWorkItem(TestMethod, "Hello"); Console.ReadKey(); } //線程函數(shù) public static void TestMethod(object data) { string datastr = data as string; Console.WriteLine(datastr); } }
五、Task類
使用ThreadPool的QueueUserWorkItem()方法發(fā)起一次異步的線程執(zhí)行很簡單,但是該方法最大的問題是沒有一個內(nèi)建的機(jī)制讓你知道操作什么時候完成,有沒有一個內(nèi)建的機(jī)制在操作完成后獲得一個返回值。為此,可以使用System.Threading.Tasks中的Task類。
構(gòu)造一個Task<TResult>對象,并為泛型TResult參數(shù)傳遞一個操作的返回類型。
class Program { static void Main(string[] args) { Task<Int32> t = new Task<Int32>(n => Sum((Int32)n), 1000); t.Start(); t.Wait(); Console.WriteLine(t.Result); Console.ReadKey(); } private static Int32 Sum(Int32 n) { Int32 sum = 0; for (; n > 0; --n) checked{ sum += n;} //結(jié)果太大,拋出異常 return sum; } }
一個任務(wù)完成時,自動啟動一個新任務(wù)。
一個任務(wù)完成后,它可以啟動另一個任務(wù),下面重寫了前面的代碼,不阻塞任何線程。
class Program { static void Main(string[] args) { Task<Int32> t = new Task<Int32>(n => Sum((Int32)n), 1000); t.Start(); //t.Wait(); Task cwt = t.ContinueWith(task => Console.WriteLine("The result is {0}", t.Result)); Console.ReadKey(); } private static Int32 Sum(Int32 n) { Int32 sum = 0; for (; n > 0; --n) checked { sum += n; } //結(jié)果溢出,拋出異常 return sum; } }
六、委托異步執(zhí)行
委托的異步調(diào)用:BeginInvoke() 和 EndInvoke()
namespace Test { public delegate string MyDelegate(object data); class Program { static void Main(string[] args) { MyDelegate mydelegate = new MyDelegate(TestMethod); IAsyncResult result = mydelegate.BeginInvoke("Thread Param", TestCallback, "Callback Param"); //異步執(zhí)行完成 string resultstr = mydelegate.EndInvoke(result); } //線程函數(shù) public static string TestMethod(object data) { string datastr = data as string; Console.WriteLine(datastr); return datastr; } //異步回調(diào)函數(shù) public static void TestCallback(IAsyncResult data) { Console.WriteLine(data.AsyncState); } } }
異步回調(diào)函數(shù)在上面線程函數(shù)執(zhí)行結(jié)束后,將要退出時執(zhí)行。
以上就是本文的全部內(nèi)容,希望對大家的學(xué)習(xí)有所幫助,也希望大家多多支持腳本之家。
相關(guān)文章
C# WinForm窗體編程中處理數(shù)字的正確操作方法
這篇文章主要介紹了C# WinForm窗體編程中處理數(shù)字的正確操作方法,本文給出了正確示例,并解釋了為什么要這么做,需要的朋友可以參考下2014-08-08C#中利用LINQ to XML與反射把任意類型的泛型集合轉(zhuǎn)換成XML格式字符串的方法
本文主要介紹了C#中利用LINQ to XML與反射把任意類型的泛型集合轉(zhuǎn)換成XML格式字符串的方法:利用反射,讀取一個類型的所有屬性,然后再把屬性轉(zhuǎn)換成XML元素的屬性或者子元素。下面注釋比較完整,需要的朋友可以看下2016-12-12解決C#中WebBrowser的DocumentCompleted事件不執(zhí)行的實(shí)現(xiàn)方法
本篇文章是對C#中WebBrowser的DocumentCompleted事件不執(zhí)行解決方法進(jìn)行了詳細(xì)的分析介紹,需要的朋友參考下2013-05-05C# 實(shí)現(xiàn)Scoket心跳機(jī)制的方法
這篇文章主要介紹了C# 實(shí)現(xiàn)Scoket心跳機(jī)制的方法,文中通過示例代碼介紹的非常詳細(xì),對大家的學(xué)習(xí)或者工作具有一定的參考學(xué)習(xí)價值,需要的朋友們下面隨著小編來一起學(xué)習(xí)學(xué)習(xí)吧2020-02-02C#利用OpenCvSharp實(shí)現(xiàn)玉米粒計數(shù)
這篇文章主要為大家詳細(xì)介紹了C#如何結(jié)合OpenCVSharp4實(shí)現(xiàn)玉米粒計數(shù),文中的示例代碼簡潔易懂,具有一定的學(xué)習(xí)價值,需要的小伙伴可以參考下2023-11-11