用《捕魚達人》去理解C#中的多線程

線程是進程中某個單一順序的控制流,是程序運行中的調度單位,是程序執行流的最小單位,一個標準的線程由線程ID,當前指令指針(PC),寄存器集合和堆棧組成。 線程本身不擁有系統資源,只擁有一點兒在運行中必不可少的資源,但它可與同屬一個進程的其它線程共享進程所擁有的所有資源。 線程也有就緒、阻塞和運行三種基本狀態。每個程序都至少有一個線程,若程序只有一個線程,那就是程序進程自己。html

CLR中有三種經常使用建立和管理線程的方式:Thread、ThreadPool、Task,下面用最簡單的例子寫出本身對這三種方式的理解:

1、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();
            }
      }
運行後屏幕以下:
小黃魚在游來游去......
大鯊魚在游來游去...... 
 

2、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();
            }

運行後屏幕以下:多線程

燈籠魚在游來游去......
大鯊魚在游來游去......
燈籠魚在游來游去......
小黃魚在游來游去......
紅鯉魚在游來游去......
因爲多線程是併發執行,由系統分配順序,因此上面的結果是隨機的 

3、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
相關文章
相關標籤/搜索