用《捕魚達人》去理解C#中的多執行緒
阿新 • • 發佈:2018-12-04
執行緒是程序中某個單一順序的控制流,是程式執行中的排程單位,是程式執行流的最小單位,一個標準的執行緒由執行緒ID,當前指令指標(PC),暫存器集合和堆疊組成。 執行緒自己不擁有系統資源,只擁有一點兒在執行中必不可少的資源,但它可與同屬一個程序的其它執行緒共享程序所擁有的全部資源。 執行緒也有就緒、阻塞和執行三種基本狀態。每一個程式都至少有一個執行緒,若程式只有一個執行緒,那就是程式程序本身。
CLR中有三種常用建立和管理執行緒的方式:Thread、ThreadPool、Task,下面用最簡單的例子寫出自己對這三種方式的理解:一、Thread
《捕魚達人》是大家都玩過的遊戲,至於遊戲怎麼設計我也不太清楚,但我想在這裡用自己對執行緒的理解來用執行緒描述這個遊戲。假如螢幕上隨機產生兩條魚,並且游來游去,程式碼如下:class執行後螢幕如下: 小黃魚在游來游去...... 大鯊魚在游來游去......Fish { public string Name { get; set; } public Fish() { Name = "小黃魚" ; } public void Move() { Console.WriteLine(string .Format("{0}在游來游去......", Name)); } }class Program { static void Main(string[] args) { Fish fish = new Fish(); Thread t1 = new Thread(() => { fish.Move(); }); t1.IsBackground = true; t1.Start(); Fish fish2 = new Fish() { Name = "大鯊魚" }; Thread t2 = new Thread(() => { fish2.Move(); }); t2.IsBackground = true; t2.Start(); Console.ReadKey(); } }
二、ThreadPool
如果魚潮來臨,一下子要產生100條魚,如果按上面Thread的做法就要開啟100條執行緒,這樣對系統資源的損耗太大,這時我們可以用ThreadPool執行緒池來實現,程式碼如下:static void Main(string[] args) { Fish fish = new Fish(); Fish fish2 = new Fish() { Name = "大鯊魚" }; Fish fish3 = new Fish() { Name = "燈籠魚" }; Fish fish4 = new Fish() { Name = "紅鯉魚" }; Fish fish100 = new Fish() { Name = "燈籠魚" }; ThreadPool.QueueUserWorkItem(f => { fish.Move(); }); ThreadPool.QueueUserWorkItem(f => { fish2.Move(); }); ThreadPool.QueueUserWorkItem(f => { fish3.Move(); }); ThreadPool.QueueUserWorkItem(f => { fish4.Move(); }); ThreadPool.QueueUserWorkItem(f => { fish100.Move(); }); Console.ReadKey(); }
執行後螢幕如下:
燈籠魚在游來游去...... 大鯊魚在游來游去...... 燈籠魚在游來游去...... 小黃魚在游來游去...... 紅鯉魚在游來游去...... 由於多執行緒是併發執行,由系統分配順序,所以上面的結果是隨機的三、Task
Task是.Net4.0中新加的功能,由於ThreadPool對池中的執行緒不好控制,Task用來彌補,比如在魚在流動的時候,我開了一個槍和炮的執行緒用來發射子彈捕魚,魚中槍後魚遊動的執行緒就要結束,結束的時候彈出獎勵積分,比如小黃魚彈出1分,大鯊魚彈出100分,這是就要用到Task物件的ContinueWith方法,該方法可以線上程結束的時候產生一個回撥方法,程式碼如下:class Program { static void Main(string[] args) { //用來取消小黃魚執行緒 CancellationTokenSource cts = new CancellationTokenSource (); Fish fish = new Fish(); Fish fish2 = new Fish() { Name = "大鯊魚" , Score =100 }; Task t1 = new Task(() => fish.Move(cts.Token), cts.Token); t1.Start(); //小黃魚被擊中後顯示積分 t1.ContinueWith(fish.ShowScore); Task t2 = new Task(() =>fish2.Move(cts.Token), cts.Token); t2.Start(); //大鯊魚魚被擊中後顯示積分 t2.ContinueWith(fish2.ShowScore); //按任意鍵發射 Console.ReadKey(); //武器工廠執行緒池,執行一組任務 Gun gun = new Gun(); LaserGun laserGun = new LaserGun(); TaskFactory taskfactory = new TaskFactory(); Task[] tasks = new Task[] { taskfactory.StartNew(()=>gun.Fire()), taskfactory.StartNew(()=>laserGun.Fire()) }; //執行武器們開火 taskfactory.ContinueWhenAll(tasks, (Task) => { }); //魚兒們被擊中了就會去調顯示積分的方法 cts.Cancel(); Console.ReadLine(); } } class Fish { public string Name { get; set; } public int Score { get; set; } public Fish() { Name = "小黃魚" ; Score = 1; } /// <summary> /// 遊動 /// </summary> public void Move(CancellationToken ct) { //如果沒有被擊中,就一直遊阿遊,用IsCancellationRequested判斷 while (!ct.IsCancellationRequested) { Console.WriteLine(string .Format("{0}在游來游去......", Name)); Thread.Sleep(1000); } } //中槍死亡後顯示獎勵 public void ShowScore(Task task) { Console.WriteLine(string .Format("{0}中彈了,您得到{1}分......" , Name, Score)); } } abstract class Weapon { public string Name { get; set; } public abstract void Fire(); } class Gun : Weapon { public Gun() : base() { Name = "雙射槍" ; } public override void Fire() { Console.WriteLine(string .Format("咻咻咻,{0}向魚兒們發射子彈......" , Name)); } } class LaserGun : Weapon { public LaserGun() : base() { Name = "鐳射炮" ; } public override void Fire() { Console.WriteLine(string .Format("嗖嗖嗖,{0}向魚兒們發射炮彈......" , Name)); } }執行後螢幕如下: 大鯊魚在游來游去...... 小黃魚在游來游去...... 大鯊魚在游來游去...... 小黃魚在游來游去...... 大鯊魚在游來游去...... 小黃魚在游來游去...... 按任意鍵開火後螢幕顯示: 大鯊魚在游來游去...... 小黃魚在游來游去...... 大鯊魚在游來游去...... 小黃魚在游來游去...... 大鯊魚在游來游去...... 小黃魚在游來游去...... 咻咻咻,雙射槍向魚兒們發射子彈...... 嗖嗖嗖,鐳射炮向魚兒們發射子彈...... 大鯊魚中彈了,您得到100分...... 小黃魚中彈了,您得到1分...... from:http://www.cnblogs.com/maitian-lf/p/3678128.html#undefined