閑話“多線程”
一,摘要
圣殿騎士首先向大家說聲對不起,由于最近身體不適,同時也因為這些天一直在研究微軟的云計算平臺Windows Azure(公司項目需要),所以暫停了更新WPF 基礎到企業應用系列索引,不過經過這幾天的調節,尤其是到海邊去曬了曬太陽,現在又開始繼續發文了,大家有興趣也可以去看看漂亮的大海圖片工作之余的閑暇,今天這篇文章不是專業談多線程,只是應一些朋友的要求對上篇文章WPF 基礎到企業應用系列4——WPF千年輪回進行一些額外的補充,如果有時間,可以單獨寫一個專題來詳細深入多線程的應用,當然由于自己才疏學淺,但渴求對自己知識的糾正和提高,所以發布出來。如有不對的地方,也希望大家多多海涵!
二,提綱
一,摘要
二,提綱
三,基本概念
四,多線程實踐
五,總結
三,基本概念
什么是進程?
“進程”是操作系統的最基本的,也是最重要的概念之一。簡單來說一個進程就是你正在執行的應用程序,一個進程里面包括一個或多個線程。系統中的一個進程肯定對應著一個應用程序,但同一個應用程序可以有多個進程。所以我們要清楚,進程和程序是相關聯的,但并不是同一個概念。即應用程序被加載到內存中后叫進程。
什么是線程?
線程簡單來說就是程序中的一個執行流,每個線程都有自己的專有寄存器同時代碼區是共享的,即不同的線程可以執行同樣的函數和訪問同樣的變量。 即進程被CPU處理時叫線程。
什么是多線程?
多線程簡單的說就是在一個程序中包含多個程序流,可以把一個復雜的操作分成多個細節操作,這些細節操作可以并行的執行,從而節約時間和提高效率。
多線程優點:
線程可以有以下一些好處:可以提高CPU的利用率。在一個多線程程序中,一個線程處于等待的時候,CPU可以運行其它的線程來處理,這樣就節約了時間和提高了程序的效率,同時也提高了用戶的體驗。
多線程缺點:
1,線程越多,內存占用越大;
2,多線程的運行需要互相協調和統一管理,CPU會額外跟蹤線程;
3,線程之間對共享資源的訪問會相互影響,必須解決競用共享資源的種種問題;
4,線程太多會導致控制的復雜度增加,會引發不必要的Bug;5,在32位的操作系統和64位的操作系統執行的線程、版本不同的操作系統之間執行的線程等都有所差異,執行順序也有差異。
重要概念(本篇不重點講解)
Start():啟動線程;
Sleep(int):暫停當前線程指定的毫秒數;
Abort():通常使用該方法來終止一個線程,但容易出錯;
Suspend():掛起線程,需要時可以恢復;
Resume():恢復被Suspend()方法掛起的線程;程的優先級可以定義為ThreadPriority枚舉的值,即Highest、AboveNormal、Normal、BelowNormal和 Lowest;
創建線程可以用如下三種方式:Thread、ThreadPool、Timer;
.NET Framework內置提供了三種Timer:System.Windows.Forms.Timer、System.Timers.Timer和System.Threading.Timer;
線程同步lock,Monitor,同步事件EventWaitHandler,互斥體Mutex、線程池等的使用;
四,多線程實踐
在本文中我們會通過11個小Demo來講解一下多線程的實踐,講得不是很全面,只是希望給大家一個參考。由于比較簡單,所以我就不添加累贅的文字介紹,這樣大家看起來也比較舒暢。我會在文章后面附上代碼,大家可以下載進行查看和調試。
這個11個方法都通過Form1_Load調用,如下面的代碼和圖片:
private void Form1_Load(object sender, EventArgs e) { DoWithEasy(); DoWithParameter(); DoWithTimer(); DoWithThreadPool(); DoWithThreadPoolParameter(); DoWithAnonymous(); DoWithLambda(); DoWithCommon(); DoWithAction(); DoWithFunc(); DoWithPredicate(); }
創建一個簡單的線程:
private void DoWithEasy() { Thread t = new Thread(new ThreadStart(this.DoSomethingWithEasy)); t.Start(); } private void DoSomethingWithEasy() { MessageBox.Show("Knights Warrior"); }
創建一個帶方法的線程:
private void DoWithParameter() { Thread t = new Thread(new ParameterizedThreadStart(this.DoSomethingWithParameter)); t.Start("Knights Warrior"); } private void DoSomethingWithParameter(object x) { MessageBox.Show(x.ToString()); }
使用Timer創建線程:
public void DoWithTimer() { System.Windows.Forms.Timer timer = new System.Windows.Forms.Timer(); timer.Interval = 1000; timer.Tick += (x, y) => { MessageBox.Show("Knights Warrior"); }; timer.Start(); }
通過ThreadPool創建無參線程:
private void DoWithThreadPool() { ThreadPool.QueueUserWorkItem(new WaitCallback(this.DoSomethingWithThreadPoolNO)); } private void DoSomethingWithThreadPoolNO(object x) { MessageBox.Show("Knights Warrior"); }
通過ThreadPool創建有參線程:
private void DoWithThreadPoolParameter() { ThreadPool.QueueUserWorkItem(new WaitCallback(this.DoSomethingWithThreadPoolParameter), "Knights Warrior"); } private void DoSomethingWithThreadPoolParameter(object x) { MessageBox.Show(x.ToString()); }
通過匿名委托方式創建線程:
private void DoWithAnonymous() { ThreadPool.QueueUserWorkItem(new WaitCallback(delegate(object x) { MessageBox.Show("Knights Warrior"); })); }
通過lambda的方式創建線程:
private void DoWithLambda() { ThreadPool.QueueUserWorkItem(new WaitCallback(x => { MessageBox.Show("Knights Warrior"); })); }
線程更新UI(自定義委托的方式):
private void DoWithCommon() { WaitCallback waitCallBack = new WaitCallback(this.InvokeMethod); ThreadPool.QueueUserWorkItem(waitCallBack, "Knights Warrior"); } private delegate void InvokeMethodDelegate(string name); private void InvokeMethod(object x) { this.Invoke(new InvokeMethodDelegate(this.ChangeUIWithCommon), x.ToString()); } private void ChangeUIWithCommon(string name) { this.lblMessage.Text = name; }
線程更新UI(通過Action委托)
private void DoWithAction() { WaitCallback waitCallback = new WaitCallback(this.DoSomethingWithAction); ThreadPool.QueueUserWorkItem(waitCallback, "Knights Warrior"); } private void DoSomethingWithAction(object x) { this.Invoke(new Action<string>(this.ChangeUI), x.ToString()); } private void ChangeUI(string message) { this.lblMessage.Text = message; }
線程更新UI(通過Func委托)
private void DoWithFunc() { WaitCallback waitCallback = new WaitCallback(this.DoSomethingWithFunc); ThreadPool.QueueUserWorkItem(waitCallback, "Knights Warrior"); } private void DoSomethingWithFunc(object x) { Func<string, int> f = new Func<string, int>(this.GetFuncMessage); object result = this.Invoke(f, x.ToString()); MessageBox.Show(result.ToString()); } private int GetFuncMessage(string message) { this.lblMessage.Text = message; if (message == "Knights Warrior") { return 1; } else { return 0; } }
線程更新UI(通過Predicate委托)
private void DoWithPredicate() { WaitCallback waitCallback = new WaitCallback(this.DoSomethingWithPredicate); ThreadPool.QueueUserWorkItem(waitCallback, "Knights Warrior"); } private void DoSomethingWithPredicate(object x) { Predicate<string> pd = new Predicate<string>(this.GetPredicateMessage); object result = this.Invoke(pd, x); MessageBox.Show(result.ToString()); } private bool GetPredicateMessage(string message) { this.lblMessage.Text = message; if (message == "Knights Warrior") { return true; } else { return false; } }
概念注解:
Predicate 委托
定義:public delegate bool Predicate(T obj);
表示定義一組條件并確定指定對象是否符合這些條件的方法。這個委托經常由 Array 和 List 類的幾種方法使用,用于在集合中檢索元素。
Func 委托
定義:public delegate TResult Func(T arg);
Func():封裝一個不具有參數并返回 TResult 的類型值的方法。
Func 封裝一個具有一個參數并返回 TResult 的類型值的方法。
Action 委托
定義:public delegate void Action(T obj);
Action:封裝一個帶有兩個參數并且返回值的方法。
這三個委托經常會用到,區分也很簡單,Predicate接受一個T的參數,返回一個bool值;Func接受0到四個參數,返回一個值;Action接受一到四個參數,無返回值;
五,總結
這篇文章并沒有什么深度和難度,只是對多線程進行了一下小結,如果大家想了解更多,我會單獨詳細寫一些,當然由于本人知識有限,文中錯誤之處也敬請海涵!下一篇開始我們將繼續更新WPF 基礎到企業應用系列索引系列文章,如果有感興趣的同仁,敬請關注!