首页 > 编程 > C# > 正文

C#多线程经典示例(吃苹果)

2019-10-29 21:15:58
字体:
来源:转载
供稿:网友

本文主要讲述了多线程开发中经典示例,通过本示例,可以加深对多线程的理解。

示例概述:

下面用一个模拟吃苹果的实例,说明C#中多线程的实现方法。要求开发一个程序实现如下情况:一个家庭有三个孩子,爸爸妈妈不断削苹果往盘子里面放,老大、老二、老三不断从盘子里面取苹果吃。盘子的大小有限,最多只能放5个苹果,并且爸妈不能同时往盘子里面放苹果,妈妈具有优先权。三个孩子取苹果时,盘子不能为空,三人不能同时取,老三优先权最高,老大最低。老大吃的最快,取的频率最高,老二次之。

涉及到知识点:

  • 线程Thread 创建并控制线程,设置其优先级并获取其状态。
  • 锁 lock 用于实现多线程同步的最直接办法就是加锁,它可以把一段代码定义为互斥段,在一个时刻内只允许一个线程进入执行,而其他线程必须等待。
  • 事件EventHandler 声明一个事件,用于通知界面做改变

设计思路:

  • Productor 表示生产者,用于削苹果。
  • Consumer 表示消费者,用于吃苹果。
  • Dish 盘子,用于装苹果,做为中间类
  • EatAppleSmp 的BeginEat()方法,表示开始吃苹果,启动线程

效果图如下【爸爸妈妈削苹果,孩子吃苹果】:

C#,多线程

后台输出如下:

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 代码如下:

using System;using System.Collections.Generic;using System.Linq;using System.Text;using System.Threading;namespace DemoSharp.EatApple{ /// <summary> /// 生产者 /// </summary> public class Productor {  private Dish dish;  private string name;  public string Name  {   get { return name; }   set { name = value; }  }  public EventHandler PutAction;//声明一个事件,当放苹果时触发该事件  public Productor(string name, Dish dish)  {   this.name = name;   this.dish = dish;  }  public void run()  {   while (true)   {    bool flag= dish.Put(name);    if (flag)    {     if (PutAction != null)     {      PutAction(this, null);     }     try     {      Thread.Sleep(600);//削苹果时间     }     catch (Exception ex)     {     }    }    else {     break;    }   }  } }}

Consumer代码如下:

using System;using System.Collections.Generic;using System.Linq;using System.Text;using System.Threading;namespace DemoSharp.EatApple{ /// <summary> /// 消费者 /// </summary> public class Consumer {  private string name;  public string Name  {   get { return name; }   set { name = value; }  }  private Dish dish;  private int timelong;  public EventHandler GetAction;//声明一个事件,当放苹果时触发该事件  public Consumer(string name, Dish dish, int timelong)  {   this.name = name;   this.dish = dish;   this.timelong = timelong;  }  public void run()  {   while (true)   {    bool flag= dish.Get(name);    if (flag)    {     //如果取到苹果,则调用事件,并开始吃     if (GetAction != null)     {      GetAction(this, null);     }     try     {      Thread.Sleep(timelong);//吃苹果时间     }     catch (ThreadInterruptedException)     {     }    }    else {     break;    }   }  } }}

Dish代码如下:

using System;using System.Collections.Generic;using System.Linq;using System.Text;using System.Threading;namespace DemoSharp.EatApple{ /// <summary> /// 盘子,属于中间类 /// </summary> public class Dish {  private int f = 5;//表示盘子中还可以放几个苹果,最多只能放5个苹果  private int EnabledNum;//可放苹果总数  private int n = 0; //表示已经放了多少个苹果  private object objGet = new object();  private object objPut = new object();  /// <summary>  /// 构造函数,初始化Dish对象  /// </summary>  /// <param name="num">表示削够多少个苹果结束</param>  public Dish(int num)  {   this.EnabledNum = num;  }  /// <summary>  /// 放苹果的方法  /// </summary>  /// <param name="name"></param>  ///<returns>是否放成功</returns>  public bool Put(string name)  {   lock (this)//同步控制放苹果   {    bool flag = false;    while (f == 0)//苹果已满,线程等待    {     try     {      System.Console.WriteLine(name + "正在等待放入苹果");      Monitor.Wait(this);     }     catch (Exception ex)     {      System.Console.WriteLine(name + "等不及了");     }    }     if (n < EnabledNum)    {     f = f - 1;//削完一个苹果放一次     n = n + 1;     System.Console.WriteLine(name + "放1个苹果");     flag = true;    }    Monitor.PulseAll(this);    return flag;   }  }  /// <summary>  /// 取苹果的方法  /// </summary>  /// <param name="name"></param>  public bool Get(string name)  {   lock (this)//同步控制取苹果   {    bool flag = false;    while (f == 5)    {     try     {      System.Console.WriteLine(name + "等待取苹果");      Monitor.Wait(this);     }     catch (ThreadInterruptedException) { }    }    if (n <= EnabledNum)    {     f = f + 1;     System.Console.WriteLine(name + "取苹果吃...");     flag = true;    }    Monitor.PulseAll(this);    return flag;   }  } } }

EatAppleSmp代码如下:

using System;using System.Collections.Generic;using System.Linq;using System.Text;using System.Threading;namespace DemoSharp.EatApple{ public class EatAppleSmp {  public EventHandler PutAction;//声明一个事件,当放苹果时触发该事件  public EventHandler GetAction;//声明一个事件,当放苹果时触发该事件  /// <summary>  /// 开始吃苹果  /// </summary>  public void BeginEat()  {   Thread th_mother, th_father, th_young, th_middle, th_old;//依次表示妈妈,爸爸,小弟,二弟,大哥   Dish dish = new Dish(30);   Productor mother = new Productor("Mama", dish);//建立线程   mother.PutAction += PutActionMethod;   Productor father = new Productor("Baba", dish);   father.PutAction += PutActionMethod;   Consumer old = new Consumer("Dage", dish, 1200);   old.GetAction += GetActionMethod;   Consumer middle = new Consumer("Erdi", dish, 1500);   middle.GetAction += GetActionMethod;   Consumer young = new Consumer("Sandi", dish, 1800);   young.GetAction += GetActionMethod;   th_mother = new Thread(new ThreadStart(mother.run));   th_mother.Name = "Mama";   th_father = new Thread(new ThreadStart(father.run));   th_father.Name = "Baba";   th_old = new Thread(new ThreadStart(old.run));   th_old.Name = "Dage";   th_middle = new Thread(new ThreadStart(middle.run));   th_middle.Name = "Erdi";   th_young = new Thread(new ThreadStart(young.run));   th_young.Name = "Sandi";   th_mother.Priority = ThreadPriority.Highest;//设置优先级   th_father.Priority = ThreadPriority.Normal;   th_old.Priority = ThreadPriority.Lowest;   th_middle.Priority = ThreadPriority.Normal;   th_young.Priority = ThreadPriority.Highest;   th_mother.Start();   th_father.Start();   th_old.Start();   th_middle.Start();   th_young.Start();  }  private void GetActionMethod(object sender,EventArgs e)  {   if (GetAction != null)   {    GetAction(sender, e);   }  }  private void PutActionMethod(object sender, EventArgs e)  {   if (PutAction != null)   {    PutAction(sender, e);   }  } }}

界面类代码如下:

using System;using System.Collections.Generic;using System.ComponentModel;using System.Data;using System.Drawing;using System.Linq;using System.Text;using System.Windows.Forms;using DemoSharp.EatApple;namespace DemoSharp{ /// <summary> /// 页面类 /// </summary> public partial class EatAppleForm : Form {  private EatAppleSmp m_EatAppleSmp = new EatAppleSmp();  public EatAppleForm()  {   InitializeComponent();   InitView();   m_EatAppleSmp.PutAction += PutActionMethod;   m_EatAppleSmp.GetAction += GetActionMethod;  }  /// <summary>  /// 初始化GroupBox  /// </summary>  private void InitView()  {   this.gbBaba.Controls.Clear();   this.gbMama.Controls.Clear();   this.gbDage.Controls.Clear();   this.gbErdi.Controls.Clear();   this.gbSandi.Controls.Clear();  }  /// <summary>  /// 启动线程  /// </summary>  /// <param name="sender"></param>  /// <param name="e"></param>  private void btnStart_Click(object sender, EventArgs e)  {   this.m_EatAppleSmp.BeginEat();  }  /// <summary>  /// 放苹果事件  /// </summary>  /// <param name="sender"></param>  /// <param name="e"></param>  private void PutActionMethod(object sender, EventArgs e)  {   Productor p = sender as Productor;   if (p != null)   {    if (p.Name == "Baba")    {     AddItemToGroupBox(this.gbBaba, this.lblBaba);    }    if (p.Name == "Mama")    {     AddItemToGroupBox(this.gbMama, this.lblMama);    }   }  }  /// <summary>  /// 吃苹果事件  /// </summary>  /// <param name="sender"></param>  /// <param name="e"></param>  public void GetActionMethod(object sender, EventArgs e)  {   Consumer c = sender as Consumer;   if (c != null)   {    if (c.Name == "Dage")    {     AddItemToGroupBox(this.gbDage, this.lblDage);    }    if (c.Name == "Erdi")    {     AddItemToGroupBox(this.gbErdi, this.lblErdi);    }    if (c.Name == "Sandi")    {     AddItemToGroupBox(this.gbSandi, this.lblSandi);    }   }  }  /// <summary>  /// 往指定的GroupBox中添加对象  /// </summary>  /// <param name="gbView"></param>  /// <param name="lbl"></param>  private void AddItemToGroupBox(GroupBox gbView,Label lbl)  {   gbView.Invoke(new Action(() =>   {    PictureBox p = new PictureBox();    p.Width = 20;    p.Height = 20;    p.Dock = DockStyle.Left;    p.Image = this.imgLst01.Images[0];    p.Margin = new Padding(2);    gbView.Controls.Add(p);   }));   //显示个数   lbl.Invoke(new Action(() => {    if (string.IsNullOrEmpty(lbl.Text))    {     lbl.Text = "0";    }    lbl.Text = (int.Parse(lbl.Text) + 1).ToString();   }));  } }}

以上就是本文的全部内容,希望本文的内容对大家的学习或者工作能带来一定的帮助,同时也希望多多支持VEVB武林网!


注:相关教程知识阅读请移步到c#教程频道。
发表评论 共有条评论
用户名: 密码:
验证码: 匿名发表