示例概述:
下面用一个模拟吃苹果的实例,说明C#中多线程的实现方法。要求开发一个程序实现如下情况:一个家庭有三个孩子,爸爸妈妈不断削苹果往盘子里面放,老大、老二、老三不断从盘子里面取苹果吃。盘子的大小有限,最多只能放5个苹果,并且爸妈不能同时往盘子里面放苹果,妈妈具有优先权。三个孩子取苹果时,盘子不能为空,三人不能同时取,老三优先权最高,老大最低。老大吃的最快,取的频率最高,老二次之。
涉及知识点:
- 线程Thread 创建并控制线程,设置其优先级并获取其状态。
- 锁 lock 用于实现多线程同步的最直接办法就是加锁,它可以把一段代码定义为互斥段,在一个时刻内只允许一个线程进入执行,而其他线程必须等待。
- 事件EventHandler 声明一个事件,用于通知界面做改变
设计思路:
- Productor 表示生产者,用于削苹果。
- Consumer 表示消费者,用于吃苹果。
- Dish 盘子,用于装苹果,做为中间类
- EatAppleSmp 的BeginEat()方法,表示开始吃苹果,启动线程
效果图
如下【爸爸妈妈削苹果,孩子吃苹果】:
核心算法
后台输出如下:
Mama放1个苹果 Baba放1个苹果 Dage取苹果吃... Erdi取苹果吃... Sandi等待取苹果 Mama放1个苹果 Sandi取苹果吃... Baba放1个苹果 Dage取苹果吃... Mama放1个苹果 Baba放1个苹果 Erdi取苹果吃... Mama放1个苹果 Baba放1个苹果 Dage取苹果吃... Sandi取苹果吃... Mama放1个苹果 Baba放1个苹果 Erdi取苹果吃... Mama放1个苹果 Baba放1个苹果 Dage取苹果吃... Mama放1个苹果 Baba放1个苹果 Sandi取苹果吃... Mama放1个苹果 Baba正在等待放入苹果 Erdi取苹果吃... Baba放1个苹果 Dage取苹果吃... Mama放1个苹果 Baba正在等待放入苹果 Mama正在等待放入苹果 Sandi取苹果吃... Baba放1个苹果 Mama正在等待放入苹果 Erdi取苹果吃... Mama放1个苹果 Dage取苹果吃... Baba放1个苹果 Mama正在等待放入苹果 Dage取苹果吃... Mama放1个苹果 Baba正在等待放入苹果 Erdi取苹果吃... Baba放1个苹果 Sandi取苹果吃... Mama放1个苹果 Baba正在等待放入苹果 Dage取苹果吃... Baba放1个苹果 Mama正在等待放入苹果 Erdi取苹果吃... Mama放1个苹果 Baba正在等待放入苹果 Sandi取苹果吃... Baba放1个苹果 Mama正在等待放入苹果 Dage取苹果吃... Mama放1个苹果 Baba正在等待放入苹果 Mama正在等待放入苹果 Erdi取苹果吃... Mama放1个苹果 Baba正在等待放入苹果 Dage取苹果吃... Baba放1个苹果 Mama正在等待放入苹果 Sandi取苹果吃... Mama放1个苹果 Baba正在等待放入苹果 Mama正在等待放入苹果 线程 'Mama' (0x1ce0) 已退出,返回值为 0 (0x0)。 线程 'Baba' (0x1888) 已退出,返回值为 0 (0x0)。 Erdi取苹果吃... Dage取苹果吃... Sandi取苹果吃... Dage取苹果吃... Erdi取苹果吃... Dage等待取苹果 Sandi等待取苹果 Erdi等待取苹果
Productor 代码如下:
1 using System; 2 using System.Collections.Generic; 3 using System.Linq; 4 using System.Text; 5 using System.Threading; 6 7 namespace DemoSharp.EatApple 8 { 9 /// <summary> 10 /// 生产者 11 /// </summary> 12 public class Productor 13 { 14 private Dish dish; 15 private string name; 16 17 public string Name 18 { 19 get { return name; } 20 set { name = value; } 21 } 22 23 public EventHandler PutAction;//声明一个事件,当放苹果时触发该事件 24 25 public Productor(string name, Dish dish) 26 { 27 this.name = name; 28 this.dish = dish; 29 } 30 public void run() 31 { 32 while (true) 33 { 34 bool flag= dish.Put(name); 35 if (flag) 36 { 37 if (PutAction != null) 38 { 39 PutAction(this, null); 40 } 41 try 42 { 43 Thread.Sleep(600);//削苹果时间 44 } 45 catch (Exception ex) 46 { 47 48 } 49 } 50 else { 51 break; 52 } 53 } 54 } 55 } 56 }
Consumer代码如下:
1 using System; 2 using System.Collections.Generic; 3 using System.Linq; 4 using System.Text; 5 using System.Threading; 6 7 namespace DemoSharp.EatApple 8 { 9 /// <summary> 10 /// 消费者 11 /// </summary> 12 public class Consumer 13 { 14 private string name; 15 16 public string Name 17 { 18 get { return name; } 19 set { name = value; } 20 } 21 private Dish dish; 22 private int timelong; 23 24 public EventHandler GetAction;//声明一个事件,当放苹果时触发该事件 25 26 public Consumer(string name, Dish dish, int timelong) 27 { 28 this.name = name; 29 this.dish = dish; 30 this.timelong = timelong; 31 } 32 public void run() 33 { 34 while (true) 35 { 36 bool flag= dish.Get(name); 37 if (flag) 38 { 39 //如果取到苹果,则调用事件,并开始吃 40 if (GetAction != null) 41 { 42 GetAction(this, null); 43 } 44 try 45 { 46 Thread.Sleep(timelong);//吃苹果时间 47 } 48 catch (ThreadInterruptedException) 49 { 50 } 51 } 52 else { 53 break; 54 } 55 } 56 } 57 } 58 }
Dish代码如下:
1 using System; 2 using System.Collections.Generic; 3 using System.Linq; 4 using System.Text; 5 using System.Threading; 6 7 namespace DemoSharp.EatApple 8 { 9 /// <summary> 10 /// 盘子,属于中间类 11 /// </summary> 12 public class Dish 13 { 14 private int f = 5;//表示盘子中还可以放几个苹果,最多只能放5个苹果 15 16 private int EnabledNum;//可放苹果总数 17 18 private int n = 0; //表示已经放了多少个苹果 19 20 private object objGet = new object(); 21 22 private object objPut = new object(); 23 24 /// <summary> 25 /// 构造函数,初始化Dish对象 26 /// </summary> 27 /// <param name="num">表示削够多少个苹果结束</param> 28 public Dish(int num) 29 { 30 this.EnabledNum = num; 31 } 32 /// <summary> 33 /// 放苹果的方法 34 /// </summary> 35 /// <param name="name"></param> 36 ///<returns>是否放成功</returns> 37 public bool Put(string name) 38 { 39 lock (this)//同步控制放苹果 40 { 41 bool flag = false; 42 43 while (f == 0)//苹果已满,线程等待 44 { 45 try 46 { 47 System.Console.WriteLine(name + "正在等待放入苹果"); 48 Monitor.Wait(this); 49 } 50 catch (Exception ex) 51 { 52 System.Console.WriteLine(name + "等不及了"); 53 } 54 } 55 if (n < EnabledNum) 56 { 57 f = f - 1;//削完一个苹果放一次 58 n = n + 1; 59 System.Console.WriteLine(name + "放1个苹果"); 60 flag = true; 61 } 62 Monitor.PulseAll(this); 63 return flag; 64 } 65 } 66 67 /// <summary> 68 /// 取苹果的方法 69 /// </summary> 70 /// <param name="name"></param> 71 public bool Get(string name) 72 { 73 lock (this)//同步控制取苹果 74 { 75 bool flag = false; 76 while (f == 5) 77 { 78 try 79 { 80 System.Console.WriteLine(name + "等待取苹果"); 81 Monitor.Wait(this); 82 } 83 catch (ThreadInterruptedException) { } 84 } 85 if (n <= EnabledNum) 86 { 87 f = f + 1; 88 System.Console.WriteLine(name + "取苹果吃..."); 89 flag = true; 90 } 91 Monitor.PulseAll(this); 92 return flag; 93 } 94 95 } 96 } 97 }
EatAppleSmp代码如下:
1 using System; 2 using System.Collections.Generic; 3 using System.Linq; 4 using System.Text; 5 using System.Threading; 6 7 namespace DemoSharp.EatApple 8 { 9 public class EatAppleSmp 10 { 11 public EventHandler PutAction;//声明一个事件,当放苹果时触发该事件 12 13 public EventHandler GetAction;//声明一个事件,当放苹果时触发该事件 14 15 /// <summary> 16 /// 开始吃苹果 17 /// </summary> 18 public void BeginEat() 19 { 20 Thread th_mother, th_father, th_young, th_middle, th_old;//依次表示妈妈,爸爸,小弟,二弟,大哥 21 Dish dish = new Dish(30); 22 Productor mother = new Productor("Mama", dish);//建立线程 23 mother.PutAction += PutActionMethod; 24 Productor father = new Productor("Baba", dish); 25 father.PutAction += PutActionMethod; 26 Consumer old = new Consumer("Dage", dish, 1200); 27 old.GetAction += GetActionMethod; 28 Consumer middle = new Consumer("Erdi", dish, 1500); 29 middle.GetAction += GetActionMethod; 30 Consumer young = new Consumer("Sandi", dish, 1800); 31 young.GetAction += GetActionMethod; 32 th_mother = new Thread(new ThreadStart(mother.run)); 33 th_mother.Name = "Mama"; 34 th_father = new Thread(new ThreadStart(father.run)); 35 th_father.Name = "Baba"; 36 th_old = new Thread(new ThreadStart(old.run)); 37 th_old.Name = "Dage"; 38 th_middle = new Thread(new ThreadStart(middle.run)); 39 th_middle.Name = "Erdi"; 40 th_young = new Thread(new ThreadStart(young.run)); 41 th_young.Name = "Sandi"; 42 th_mother.Priority = ThreadPriority.Highest;//设置优先级 43 th_father.Priority = ThreadPriority.Normal; 44 th_old.Priority = ThreadPriority.Lowest; 45 th_middle.Priority = ThreadPriority.Normal; 46 th_young.Priority = ThreadPriority.Highest; 47 th_mother.Start(); 48 th_father.Start(); 49 th_old.Start(); 50 th_middle.Start(); 51 th_young.Start(); 52 } 53 54 private void GetActionMethod(object sender,EventArgs e) 55 { 56 if (GetAction != null) 57 { 58 GetAction(sender, e); 59 } 60 } 61 62 private void PutActionMethod(object sender, EventArgs e) 63 { 64 if (PutAction != null) 65 { 66 PutAction(sender, e); 67 } 68 } 69 } 70 }
界面类代码如下:
1 using System; 2 using System.Collections.Generic; 3 using System.ComponentModel; 4 using System.Data; 5 using System.Drawing; 6 using System.Linq; 7 using System.Text; 8 using System.Windows.Forms; 9 using DemoSharp.EatApple; 10 11 namespace DemoSharp 12 { 13 /// <summary> 14 /// 页面类 15 /// </summary> 16 public partial class EatAppleForm : Form 17 { 18 private EatAppleSmp m_EatAppleSmp = new EatAppleSmp(); 19 20 public EatAppleForm() 21 { 22 InitializeComponent(); 23 InitView(); 24 m_EatAppleSmp.PutAction += PutActionMethod; 25 m_EatAppleSmp.GetAction += GetActionMethod; 26 } 27 28 /// <summary> 29 /// 初始化GroupBox 30 /// </summary> 31 private void InitView() 32 { 33 this.gbBaba.Controls.Clear(); 34 this.gbMama.Controls.Clear(); 35 this.gbDage.Controls.Clear(); 36 this.gbErdi.Controls.Clear(); 37 this.gbSandi.Controls.Clear(); 38 } 39 40 /// <summary> 41 /// 启动线程 42 /// </summary> 43 /// <param name="sender"></param> 44 /// <param name="e"></param> 45 private void btnStart_Click(object sender, EventArgs e) 46 { 47 this.m_EatAppleSmp.BeginEat(); 48 } 49 50 /// <summary> 51 /// 放苹果事件 52 /// </summary> 53 /// <param name="sender"></param> 54 /// <param name="e"></param> 55 private void PutActionMethod(object sender, EventArgs e) 56 { 57 Productor p = sender as Productor; 58 if (p != null) 59 { 60 if (p.Name == "Baba") 61 { 62 AddItemToGroupBox(this.gbBaba, this.lblBaba); 63 } 64 if (p.Name == "Mama") 65 { 66 AddItemToGroupBox(this.gbMama, this.lblMama); 67 } 68 } 69 } 70 71 /// <summary> 72 /// 吃苹果事件 73 /// </summary> 74 /// <param name="sender"></param> 75 /// <param name="e"></param> 76 public void GetActionMethod(object sender, EventArgs e) 77 { 78 Consumer c = sender as Consumer; 79 if (c != null) 80 { 81 if (c.Name == "Dage") 82 { 83 AddItemToGroupBox(this.gbDage, this.lblDage); 84 } 85 if (c.Name == "Erdi") 86 { 87 AddItemToGroupBox(this.gbErdi, this.lblErdi); 88 } 89 if (c.Name == "Sandi") 90 { 91 AddItemToGroupBox(this.gbSandi, this.lblSandi); 92 } 93 } 94 } 95 96 /// <summary> 97 /// 往指定的GroupBox中添加对象 98 /// </summary> 99 /// <param name="gbView"></param> 100 /// <param name="lbl"></param> 101 private void AddItemToGroupBox(GroupBox gbView,Label lbl) 102 { 103 gbView.Invoke(new Action(() => 104 { 105 PictureBox p = new PictureBox(); 106 p.Width = 20; 107 p.Height = 20; 108 p.Dock = DockStyle.Left; 109 p.Image = this.imgLst01.Images[0]; 110 p.Margin = new Padding(2); 111 gbView.Controls.Add(p); 112 113 })); 114 //显示个数 115 lbl.Invoke(new Action(() => { 116 if (string.IsNullOrEmpty(lbl.Text)) 117 { 118 lbl.Text = "0"; 119 } 120 lbl.Text = (int.Parse(lbl.Text) + 1).ToString(); 121 })); 122 } 123 } 124 }
源码下载链接,请点击: