C# 多线程-- Monitor
以下内容摘自《C#2.0完全参考手册》:(程序代码有所修改)
线程T正在Lock块内执行,此时需要暂时不可用的资源R,那么T该做什么呢?如果T等待R资源可用,那么有可能进入某种死循环,因为T将冻结Lock块内的对象,
组织其他的进程访问。这样看来,加锁不是一个最佳的解决方案,因为它局部地抵消了多线程编程的优点。更好的解决方案是让T暂时放弃对对象的的控制,允许
其他进程运行。当R变得可用时,就通知T让它恢复执行。这种方式的实现依赖于线程间的通信。 在这里要做的是使一个线程能够让位于另一个被中断的线程,并
在能够继续运行时被唤醒。C#利用Wait(),Pulse(),PulseAll()等方法来实现线程间的通信。
Wait(),Pulse(),PulseAll()方法由Monitor类定义,只能从锁定的代码块内调用这些方法…… 线程在被暂时中断运行时调用Wait()方法,这使得线程暂时进入休
眠状态并释放对象的锁以允许其他线程使用此对象。 当其他线程使用完锁对象调用Pluse()或PluseAll()时,唤醒休眠的进程。Pluse()被调用时将恢复等待锁的线
程队列中的第一个线程,而调用PluseAll()表示将锁释放给所有正在等待的线程。

Code
1 using System;
2 using System.Collections.Generic;
3 using System.Linq;
4 using System.Text;
5
6 using System.Threading;
7
8 namespace thread
9 {
10 //程序随时间的推移不断的同步输出“Tick ”和“Tock”,即不断的重复输出“Tick”后跟“Tock”
11
12 class TickTock
13 {
14 public void tick(bool running)
15 {
16 lock (this)
17 {
18 if (!running)
19 {
20 return;
21 }
22 //Sleep只是为了便于清晰的查看效果
23 Thread.Sleep(2000);
24 Console.WriteLine("Tick得到资源…… TickTickTickTick");
25
26 //唤醒其他进程,自己本身还在运行,而且还在lock
27 Monitor.Pulse(this);
28 Thread.Sleep(2000);
29 Console.WriteLine("Tick释放资源……\n" );
30
31 //线程暂时被中断----使线程暂时进入休眠状态,并释放对象的锁以允许其他线程使用此对象
32 Monitor.Wait(this);
33
34 //线程重新获取资源后输出---另一个线程释放资源后,使该资源重新获取资源
35 Console.WriteLine("Tick重新获取到资源……");
36 }
37 }
38
39 public void tock(bool running)
40 {
41 //注释同上
42 lock (this)
43 {
44 if (!running)
45 {
46 Monitor.Pulse(this);
47 return;
48 }
49 Thread.Sleep(2000);
50 Console.WriteLine("Tock得到资源…… TockTockTockTock");
51
52 Monitor.Pulse(this);
53 Thread.Sleep(2000);
54 Console.WriteLine("Tock释放资源……\n");
55
56 Monitor.Wait(this);
57 Console.WriteLine("Tock重新获取到资源……");
58 }
59 }
60 }
61
62 class TestMonitor
63 {
64 public Thread thrd;
65 TickTock ttob;
66
67 public TestMonitor(string name, TickTock tt)
68 {
69 thrd = new Thread(this.run);
70 ttob = tt;
71 thrd.Name = name;
72 thrd.Start();
73 }
74
75 void run()
76 {
77 if (thrd.Name == "Tick")
78 {
79 //调用Tick
80 for (int i = 0; i < 4; i++)
81 {
82 ttob.tick(true);
83 }
84 ttob.tick(false);
85 }
86 else
87 {
88 //调用Tock
89 for (int i = 0; i < 4; i++)
90 {
91 ttob.tock(true);
92 }
93 ttob.tock(false);
94 }
95 }
96
97 }
98
99 class TickingClock
100 {
101 public static void Main()
102 {
103 TickTock tt = new TickTock();
104
105 //多个线程,
106 TestMonitor mt1 = new TestMonitor("Tick", tt);
107 TestMonitor mt2 = new TestMonitor("Tock", tt);
108
109 mt1.thrd.Join();
110 mt2.thrd.Join();
111
112 //线程执行完毕
113 Console.WriteLine("\n Clock stopped");
114
115 }
116 }
117 }
118 下面这个可以作为对比

Code
1 using System;
2 using System.Collections.Generic;
3 using System.Linq;
4 using System.Text;
5
6 using System.Threading;
7
8 namespace thread
9 {
10 class TickTock
11 {
12 public void tick(bool running)
13 {
14 lock (this)
15 {
16 if (!running)
17 {
18 return;
19 }
20 Console.WriteLine("Tick得到资源…… TickTickTickTick");
21 }
22 }
23
24 public void tock(bool running)
25 {
26
27 lock (this)
28 {
29 if (!running)
30 {
31 return;
32 }
33 Console.WriteLine("Tock得到资源…… TockTockTockTock");
34 }
35 }
36 }
37
38 class TestMonitor
39 {
40 public Thread thrd;
41 TickTock ttob;
42
43 public TestMonitor(string name, TickTock tt)
44 {
45 thrd = new Thread(this.run);
46 ttob = tt;
47 thrd.Name = name;
48 thrd.Start();
49 }
50
51 void run()
52 {
53 if (thrd.Name == "Tick")
54 {
55 for (int i = 0; i < 4; i++)
56 {
57 ttob.tick(true);
58 }
59 ttob.tick(false);
60 }
61 else
62 {
63 for (int i = 0; i < 4; i++)
64 {
65 ttob.tock(true);
66 }
67 ttob.tock(false);
68 }
69 }
70
71 }
72
73 class TickingClock
74 {
75 public static void Main()
76 {
77 TickTock tt = new TickTock();
78
79 TestMonitor mt1 = new TestMonitor("Tick", tt);
80 TestMonitor mt2 = new TestMonitor("Tock", tt);
81
82 mt1.thrd.Join();
83 mt2.thrd.Join();
84
85 Console.WriteLine("\n Clock stopped");
86
87 }
88 }
89 }
90
线程T正在Lock块内执行,此时需要暂时不可用的资源R,那么T该做什么呢?如果T等待R资源可用,那么有可能进入某种死循环,因为T将冻结Lock块内的对象,
组织其他的进程访问。这样看来,加锁不是一个最佳的解决方案,因为它局部地抵消了多线程编程的优点。更好的解决方案是让T暂时放弃对对象的的控制,允许
其他进程运行。当R变得可用时,就通知T让它恢复执行。这种方式的实现依赖于线程间的通信。 在这里要做的是使一个线程能够让位于另一个被中断的线程,并
在能够继续运行时被唤醒。C#利用Wait(),Pulse(),PulseAll()等方法来实现线程间的通信。
Wait(),Pulse(),PulseAll()方法由Monitor类定义,只能从锁定的代码块内调用这些方法…… 线程在被暂时中断运行时调用Wait()方法,这使得线程暂时进入休
眠状态并释放对象的锁以允许其他线程使用此对象。 当其他线程使用完锁对象调用Pluse()或PluseAll()时,唤醒休眠的进程。Pluse()被调用时将恢复等待锁的线
程队列中的第一个线程,而调用PluseAll()表示将锁释放给所有正在等待的线程。
1 using System;
2 using System.Collections.Generic;
3 using System.Linq;
4 using System.Text;
5
6 using System.Threading;
7
8 namespace thread
9 {
10 //程序随时间的推移不断的同步输出“Tick ”和“Tock”,即不断的重复输出“Tick”后跟“Tock”
11
12 class TickTock
13 {
14 public void tick(bool running)
15 {
16 lock (this)
17 {
18 if (!running)
19 {
20 return;
21 }
22 //Sleep只是为了便于清晰的查看效果
23 Thread.Sleep(2000);
24 Console.WriteLine("Tick得到资源…… TickTickTickTick");
25
26 //唤醒其他进程,自己本身还在运行,而且还在lock
27 Monitor.Pulse(this);
28 Thread.Sleep(2000);
29 Console.WriteLine("Tick释放资源……\n" );
30
31 //线程暂时被中断----使线程暂时进入休眠状态,并释放对象的锁以允许其他线程使用此对象
32 Monitor.Wait(this);
33
34 //线程重新获取资源后输出---另一个线程释放资源后,使该资源重新获取资源
35 Console.WriteLine("Tick重新获取到资源……");
36 }
37 }
38
39 public void tock(bool running)
40 {
41 //注释同上
42 lock (this)
43 {
44 if (!running)
45 {
46 Monitor.Pulse(this);
47 return;
48 }
49 Thread.Sleep(2000);
50 Console.WriteLine("Tock得到资源…… TockTockTockTock");
51
52 Monitor.Pulse(this);
53 Thread.Sleep(2000);
54 Console.WriteLine("Tock释放资源……\n");
55
56 Monitor.Wait(this);
57 Console.WriteLine("Tock重新获取到资源……");
58 }
59 }
60 }
61
62 class TestMonitor
63 {
64 public Thread thrd;
65 TickTock ttob;
66
67 public TestMonitor(string name, TickTock tt)
68 {
69 thrd = new Thread(this.run);
70 ttob = tt;
71 thrd.Name = name;
72 thrd.Start();
73 }
74
75 void run()
76 {
77 if (thrd.Name == "Tick")
78 {
79 //调用Tick
80 for (int i = 0; i < 4; i++)
81 {
82 ttob.tick(true);
83 }
84 ttob.tick(false);
85 }
86 else
87 {
88 //调用Tock
89 for (int i = 0; i < 4; i++)
90 {
91 ttob.tock(true);
92 }
93 ttob.tock(false);
94 }
95 }
96
97 }
98
99 class TickingClock
100 {
101 public static void Main()
102 {
103 TickTock tt = new TickTock();
104
105 //多个线程,
106 TestMonitor mt1 = new TestMonitor("Tick", tt);
107 TestMonitor mt2 = new TestMonitor("Tock", tt);
108
109 mt1.thrd.Join();
110 mt2.thrd.Join();
111
112 //线程执行完毕
113 Console.WriteLine("\n Clock stopped");
114
115 }
116 }
117 }
118
1 using System;
2 using System.Collections.Generic;
3 using System.Linq;
4 using System.Text;
5
6 using System.Threading;
7
8 namespace thread
9 {
10 class TickTock
11 {
12 public void tick(bool running)
13 {
14 lock (this)
15 {
16 if (!running)
17 {
18 return;
19 }
20 Console.WriteLine("Tick得到资源…… TickTickTickTick");
21 }
22 }
23
24 public void tock(bool running)
25 {
26
27 lock (this)
28 {
29 if (!running)
30 {
31 return;
32 }
33 Console.WriteLine("Tock得到资源…… TockTockTockTock");
34 }
35 }
36 }
37
38 class TestMonitor
39 {
40 public Thread thrd;
41 TickTock ttob;
42
43 public TestMonitor(string name, TickTock tt)
44 {
45 thrd = new Thread(this.run);
46 ttob = tt;
47 thrd.Name = name;
48 thrd.Start();
49 }
50
51 void run()
52 {
53 if (thrd.Name == "Tick")
54 {
55 for (int i = 0; i < 4; i++)
56 {
57 ttob.tick(true);
58 }
59 ttob.tick(false);
60 }
61 else
62 {
63 for (int i = 0; i < 4; i++)
64 {
65 ttob.tock(true);
66 }
67 ttob.tock(false);
68 }
69 }
70
71 }
72
73 class TickingClock
74 {
75 public static void Main()
76 {
77 TickTock tt = new TickTock();
78
79 TestMonitor mt1 = new TestMonitor("Tick", tt);
80 TestMonitor mt2 = new TestMonitor("Tock", tt);
81
82 mt1.thrd.Join();
83 mt2.thrd.Join();
84
85 Console.WriteLine("\n Clock stopped");
86
87 }
88 }
89 }
90

浙公网安备 33010602011771号