Heim >Backend-Entwicklung >C#.Net-Tutorial >C# klassisches Beispiel für Multithreading, das Äpfel isst
In diesem Artikel geht es hauptsächlich um klassische Beispiele in der Multithreading-Entwicklung. Anhand dieses Beispiels können Sie Ihr Verständnis von Multithreading vertiefen.
Beispielübersicht:
Im Folgenden wird ein Beispiel für die Simulation des Essens eines Apfels verwendet, um die Implementierungsmethode von Multithreading in C# zu veranschaulichen. Es ist erforderlich, ein Programm zu entwickeln, um die folgende Situation zu realisieren: In einer Familie gibt es drei Kinder, die ständig Äpfel schälen und auf den Teller legen. Das älteste, zweit- und drittälteste Kind nimmt ständig Äpfel vom Teller. Die Größe des Tellers ist begrenzt und es können höchstens 5 Äpfel gleichzeitig auf den Teller gelegt werden. Wenn drei Kinder Äpfel nehmen, dürfen die Teller nicht leer sein und die drei Kinder können sie nicht gleichzeitig nehmen. Das dritte Kind hat die höchste Priorität und das älteste Kind die niedrigste. Der Älteste isst am schnellsten und nimmt am häufigsten, gefolgt vom Zweitältesten.
Einbeziehen von Wissenspunkten:
Thread Thread erstellt und steuert einen Thread, legt seine Priorität fest und erhält seinen Status.
Sperren sperren Der direkteste Weg, eine Multithread-Synchronisation zu erreichen, ist das Sperren. Es kann einen Codeabschnitt als sich gegenseitig ausschließendes Segment definieren, sodass jeweils nur ein Thread ausgeführt werden kann, während andere Threads dies tun müssen Warten.
Event EventHandler deklariert ein Ereignis, um die Schnittstelle zu benachrichtigen, Änderungen vorzunehmen
Designidee:
Productor stellt den Produzenten dar, der zum Schälen von Äpfeln verwendet wird.
Verbraucher stellt den Verbraucher dar, der es gewohnt ist, Äpfel zu essen.
Teller, der zum Aufbewahren von Äpfeln verwendet wird, als Zwischenklasse
BeginEat()-Methode von EatAppleSmp, was bedeutet, mit dem Essen von Äpfeln zu beginnen und den Thread zu starten
--- ---- ---------------------------------------------- ---- ----------------------------------------
Das Rendering ist wie folgt [Mama und Papa schälen Äpfel, Kinder essen Äpfel]:
Die Hintergrundausgabe ist wie folgt:
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等待取苹果
Produktcode lautet wie folgt:
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; } } } } }
Der Verbrauchercode lautet wie folgt:
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"; 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; } } } } } } lbl.Text = (int.Parse(lbl.Text) + 1).ToString(); })); } } }
Dish-Code lautet wie folgt:
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; } } } }
Der EatAppleSmp-Code lautet wie folgt:
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); } } } }
Der Schnittstellenklassencode lautet wie folgt:
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(); })); } } }
Weitere klassische C#-Multithreading-Beispiele für Artikel zum Thema „Äpfel essen“ finden Sie auf der chinesischen PHP-Website!