이 글에서는 주로 멀티스레딩 개발의 전형적인 예시를 다루고 있습니다. 이 예시를 통해 멀티스레딩에 대한 이해를 심화할 수 있습니다.
예제 개요:
다음은 C#에서 멀티스레딩을 구현하는 방법을 설명하기 위해 사과 먹기를 시뮬레이션하는 예를 사용합니다. 다음과 같은 상황을 실현할 수 있는 프로그램 개발이 필요합니다. 한 가족에 세 자녀가 있는데, 부모가 계속 사과를 껍질을 벗겨 접시에 올려 놓습니다. 접시의 크기는 제한되어 있으며 사과는 최대 5개까지만 놓을 수 있습니다. 사과는 부모가 동시에 접시에 담을 수 없으며 어머니가 우선권을 가집니다. 세 아이가 사과를 가져갈 때 접시는 비울 수 없으며 세 아이가 동시에 가져갈 수 없습니다. 세 번째 아이가 가장 높은 우선순위를 갖고 가장 큰 아이가 가장 낮은 우선순위를 갖습니다. 가장 나이 많은 사람이 가장 빨리 먹고 가장 자주 섭취하며, 그 다음이 두 번째입니다.
지식 포인트 포함:
Thread 스레드는 스레드를 생성하고 제어하며 우선 순위를 설정하고 상태를 얻습니다.
잠금 잠금 다중 스레드 동기화를 달성하는 가장 직접적인 방법은 코드 조각을 상호 배타적인 세그먼트로 정의하여 한 번에 하나의 스레드만 실행되도록 허용하고 다른 스레드는 반드시 실행되도록 하는 것입니다. 기다리다.
이벤트 EventHandler는 변경 사항을 인터페이스에 알리는 이벤트를 선언합니다.
디자인 아이디어:
Productor는 사과 껍질을 벗기는 데 사용되는 생산자를 나타냅니다.
소비자는 사과를 먹던 소비자를 의미합니다.
사과를 담는 데 사용되는 접시, 중급
사과 먹기 시작하고 스레드 시작을 의미하는 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等待取苹果
제품 코드는 다음과 같습니다.
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; } } } } }
소비자 코드
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 코드는
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(); })); } } }
더 많은 C# 멀티스레딩 클래식 예제 사과 먹기 관련 글은 PHP 중국어 홈페이지를 주목해주세요!