程序師世界是廣大編程愛好者互助、分享、學習的平台,程序師世界有你更精彩!
首頁
編程語言
C語言|JAVA編程
Python編程
網頁編程
ASP編程|PHP編程
JSP編程
數據庫知識
MYSQL數據庫|SqlServer數據庫
Oracle數據庫|DB2數據庫
 程式師世界 >> 編程語言 >> .NET網頁編程 >> C# >> C#基礎知識 >> C# 多線程經典示例 吃蘋果

C# 多線程經典示例 吃蘋果

編輯:C#基礎知識
本文主要講述了多線程開發中經典示例,通過本示例,可以加深對多線程的理解。 示例概述:   下面用一個模擬吃蘋果的實例,說明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 }
View Code

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 }
View Code

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 }
View Code

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 }
View Code

界面類代碼如下:

  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 }
View Code

 

 
  1. 上一頁:
  2. 下一頁:
Copyright © 程式師世界 All Rights Reserved