白话并发冲突与线程同步(3)——Mutex、EventWaitHandle、AutoResetEvent 和 ManualResetEvent
来源:互联网 发布:java中wait和notify 编辑:程序博客网 时间:2024/04/29 16:15
不过这热气是从实在的火里发出来的呢,还是从他的爱情里发出来的呢,他完全不知道。他的一切光彩现在都没有了。这是因为他在旅途中失去了呢,还是悲愁的结果,谁也说不出来。
——安徒生
摘自《坚定的锡兵》
摘要
1-2-3翻开那《葵花宝典》,只见页首赫然写着几个大字:“欲练神功,必先自宫”,旁边几行歪歪扭扭的小字,又不知是哪位前辈高人所写:“在WC里占蹲位的3种方法:1. 如果你只对某个蹲位情有独钟,就要WaitOne(),但是不要忘了ReleaseMutex(),千万别WaitOne()两次只ReleaseMutex()一次(你干这种占着MK不LS的事,憋坏了后来的小朋友怎么办?就算没有小朋友,撇坏了小猫小狗也不好啊……);2. 如果你喜欢讲排场,需要占2个蹲位才肯办事,则要WaitAll([蹲位1, 蹲位2]);3. 如果你觉得随便去哪个蹲位办事都无所谓,那就可以WaitAny([蹲位1, 蹲位2])……”。
Mutex的WaitOne()函数
前几天1-2-3去黑木崖找东方不败玩,听到东方不败抱怨说整天绣花眼睛好累呀,于是1-2-3就给东方不败编了一个活动眼睛的程序。
接连运行此程序的两个实例,把它们并排排放在一起(如下图所示),即可看到箭头从左边的窗体“穿越”到右边窗体的效果了。
是的,我们需要同步两个进程(中的主线程),这个工作需要交给Mutex。Mutex和Monitor的概念十分相似,只不过Monitor是.net内建的线程同步机制,Mutex是封装了Windows操作系统的线程同步机制;Monitor速度快,Mutex的速度要比Monitor慢很多;Monitor只能用于同步同一进程内的线程;Mutex则可以用于同步隶属于不同进程的线程。
Mutex的WaitAll()函数
现在我们对WC进行了扩建,把mk增加到两个,可是却遇到了两个讲排场的进程,它们都要同时占两个mk才肯办事,所以运行起来的效果和前一个程序一样。
Mutex的WaitAny()函数
看下这个小程序
如果同时运行此程序的两个实例,正如本文摘要里所写的,只要mk1和mk2有一个是空闲的,进程就可以进去办事,所以两个进程可以同时输出">"字符。注意程序的第24行,每个进程在输出30个">"字符后都会随机Sleep 100到3000毫秒,这样就有可能出现mk1和mk2同时空闲的情况,所以就会出现一会儿进程1占用mk1而进程2占用mk2;一会儿进程1占用mk2而进程2占用mk1的情况(在下图分别用绿色和红色波浪线标出)。
EventWaitHandle、AutoResetEvent 和 ManualResetEvent
EventWaitHandle的名字与Mutex差了很多,不过它可是Mutex不折不扣的兄弟——它和Mutex都是WaitHandle的子类,用法也差不多。下面这两段程序实现了与本文的第一段程序相同的功能。
AutoResetEvent 和 ManualResetEvent 是 EventWaitHandle 的子类,功能都差不多,就不多说了。
(本系列完)
——安徒生
摘自《坚定的锡兵》
摘要
1-2-3翻开那《葵花宝典》,只见页首赫然写着几个大字:“欲练神功,必先自宫”,旁边几行歪歪扭扭的小字,又不知是哪位前辈高人所写:“在WC里占蹲位的3种方法:1. 如果你只对某个蹲位情有独钟,就要WaitOne(),但是不要忘了ReleaseMutex(),千万别WaitOne()两次只ReleaseMutex()一次(你干这种占着MK不LS的事,憋坏了后来的小朋友怎么办?就算没有小朋友,撇坏了小猫小狗也不好啊……);2. 如果你喜欢讲排场,需要占2个蹲位才肯办事,则要WaitAll([蹲位1, 蹲位2]);3. 如果你觉得随便去哪个蹲位办事都无所谓,那就可以WaitAny([蹲位1, 蹲位2])……”。
Mutex的WaitOne()函数
前几天1-2-3去黑木崖找东方不败玩,听到东方不败抱怨说整天绣花眼睛好累呀,于是1-2-3就给东方不败编了一个活动眼睛的程序。
class Program
{
static void Main(string[] args)
{
// 为截图方便把窗体设小一点
Console.WindowWidth = 30; Console.BufferWidth = 30;
Console.WindowHeight = 16; Console.BufferHeight = 16;
Mutex mk = new Mutex(false, "my mutex");
for (int i = 0; i < 1000; i++)
{
mk.WaitOne();
for (int j = 0; j < 30; j++)
{
Console.Write(">");
Thread.Sleep(100);
}
mk.ReleaseMutex();
Thread.Sleep(500);
}
}
}
{
static void Main(string[] args)
{
// 为截图方便把窗体设小一点
Console.WindowWidth = 30; Console.BufferWidth = 30;
Console.WindowHeight = 16; Console.BufferHeight = 16;
Mutex mk = new Mutex(false, "my mutex");
for (int i = 0; i < 1000; i++)
{
mk.WaitOne();
for (int j = 0; j < 30; j++)
{
Console.Write(">");
Thread.Sleep(100);
}
mk.ReleaseMutex();
Thread.Sleep(500);
}
}
}
接连运行此程序的两个实例,把它们并排排放在一起(如下图所示),即可看到箭头从左边的窗体“穿越”到右边窗体的效果了。
是的,我们需要同步两个进程(中的主线程),这个工作需要交给Mutex。Mutex和Monitor的概念十分相似,只不过Monitor是.net内建的线程同步机制,Mutex是封装了Windows操作系统的线程同步机制;Monitor速度快,Mutex的速度要比Monitor慢很多;Monitor只能用于同步同一进程内的线程;Mutex则可以用于同步隶属于不同进程的线程。
Mutex的WaitAll()函数
现在我们对WC进行了扩建,把mk增加到两个,可是却遇到了两个讲排场的进程,它们都要同时占两个mk才肯办事,所以运行起来的效果和前一个程序一样。
class Program
{
static void Main(string[] args)
{
// 为截图方便把窗体设小一点
Console.WindowWidth = 30; Console.BufferWidth = 30;
Console.WindowHeight = 16; Console.BufferHeight = 16;
Mutex mk1 = new Mutex(false, "my mutex1");
Mutex mk2 = new Mutex(false, "my mutex2");
Mutex[] mks = new Mutex[] { mk1, mk2 };
for (int i = 0; i < 1000; i++)
{
Mutex.WaitAll(mks);
for (int j = 0; j < 30; j++)
{
Console.Write(">");
Thread.Sleep(100);
}
mk1.ReleaseMutex();
mk2.ReleaseMutex();
Thread.Sleep(500);
}
}
}
{
static void Main(string[] args)
{
// 为截图方便把窗体设小一点
Console.WindowWidth = 30; Console.BufferWidth = 30;
Console.WindowHeight = 16; Console.BufferHeight = 16;
Mutex mk1 = new Mutex(false, "my mutex1");
Mutex mk2 = new Mutex(false, "my mutex2");
Mutex[] mks = new Mutex[] { mk1, mk2 };
for (int i = 0; i < 1000; i++)
{
Mutex.WaitAll(mks);
for (int j = 0; j < 30; j++)
{
Console.Write(">");
Thread.Sleep(100);
}
mk1.ReleaseMutex();
mk2.ReleaseMutex();
Thread.Sleep(500);
}
}
}
Mutex的WaitAny()函数
看下这个小程序
1 class Program
2 {
3 static void Main(string[] args)
4 {
5 // 为截图方便把窗体设小一点
6 Console.WindowWidth = 30; Console.BufferWidth = 30;
7 Console.WindowHeight = 16; Console.BufferHeight = 16;
8
9 Mutex mk1 = new Mutex(false, "my mutex1");
10 Mutex mk2 = new Mutex(false, "my mutex2");
11 Mutex[] mks = new Mutex[] { mk1, mk2 };
12
13 for (int i = 0; i < 1000; i++)
14 {
15 int index = Mutex.WaitAny(mks); // 返回值为此进程占用的mk在mks里的index
16 Console.Write("Index: " + index.ToString());
17 for (int j = 0; j < 30; j++)
18 {
19 Console.Write(">");
20 Thread.Sleep(100);
21 }
22
23 mks[index].ReleaseMutex();
24 Thread.Sleep(new Random().Next(100, 3000));
25 }
26 }
27 }
2 {
3 static void Main(string[] args)
4 {
5 // 为截图方便把窗体设小一点
6 Console.WindowWidth = 30; Console.BufferWidth = 30;
7 Console.WindowHeight = 16; Console.BufferHeight = 16;
8
9 Mutex mk1 = new Mutex(false, "my mutex1");
10 Mutex mk2 = new Mutex(false, "my mutex2");
11 Mutex[] mks = new Mutex[] { mk1, mk2 };
12
13 for (int i = 0; i < 1000; i++)
14 {
15 int index = Mutex.WaitAny(mks); // 返回值为此进程占用的mk在mks里的index
16 Console.Write("Index: " + index.ToString());
17 for (int j = 0; j < 30; j++)
18 {
19 Console.Write(">");
20 Thread.Sleep(100);
21 }
22
23 mks[index].ReleaseMutex();
24 Thread.Sleep(new Random().Next(100, 3000));
25 }
26 }
27 }
如果同时运行此程序的两个实例,正如本文摘要里所写的,只要mk1和mk2有一个是空闲的,进程就可以进去办事,所以两个进程可以同时输出">"字符。注意程序的第24行,每个进程在输出30个">"字符后都会随机Sleep 100到3000毫秒,这样就有可能出现mk1和mk2同时空闲的情况,所以就会出现一会儿进程1占用mk1而进程2占用mk2;一会儿进程1占用mk2而进程2占用mk1的情况(在下图分别用绿色和红色波浪线标出)。
EventWaitHandle、AutoResetEvent 和 ManualResetEvent
EventWaitHandle的名字与Mutex差了很多,不过它可是Mutex不折不扣的兄弟——它和Mutex都是WaitHandle的子类,用法也差不多。下面这两段程序实现了与本文的第一段程序相同的功能。
1) AutoReset
class Program
{
static void Main(string[] args)
{
// 为截图方便把窗体设小一点
Console.WindowWidth = 30; Console.BufferWidth = 30;
Console.WindowHeight = 16; Console.BufferHeight = 16;
EventWaitHandle mk = new EventWaitHandle(true, EventResetMode.AutoReset, "my mk");
for (int i = 0; i < 1000; i++)
{
mk.WaitOne();
for (int j = 0; j < 30; j++)
{
Console.Write(">");
Thread.Sleep(100);
}
mk.Set();
Thread.Sleep(500);
}
}
}
class Program
{
static void Main(string[] args)
{
// 为截图方便把窗体设小一点
Console.WindowWidth = 30; Console.BufferWidth = 30;
Console.WindowHeight = 16; Console.BufferHeight = 16;
EventWaitHandle mk = new EventWaitHandle(true, EventResetMode.AutoReset, "my mk");
for (int i = 0; i < 1000; i++)
{
mk.WaitOne();
for (int j = 0; j < 30; j++)
{
Console.Write(">");
Thread.Sleep(100);
}
mk.Set();
Thread.Sleep(500);
}
}
}
2) ManualReset
class Program
{
static void Main(string[] args)
{
// 为截图方便把窗体设小一点
Console.WindowWidth = 30; Console.BufferWidth = 30;
Console.WindowHeight = 16; Console.BufferHeight = 16;
EventWaitHandle mk = new EventWaitHandle(true, EventResetMode.ManualReset, "my mk");
for (int i = 0; i < 1000; i++)
{
mk.WaitOne();
mk.Reset(); // 把这行去掉会咋样?
for (int j = 0; j < 30; j++)
{
Console.Write(">");
Thread.Sleep(100);
}
mk.Set();
Thread.Sleep(500);
}
}
}
class Program
{
static void Main(string[] args)
{
// 为截图方便把窗体设小一点
Console.WindowWidth = 30; Console.BufferWidth = 30;
Console.WindowHeight = 16; Console.BufferHeight = 16;
EventWaitHandle mk = new EventWaitHandle(true, EventResetMode.ManualReset, "my mk");
for (int i = 0; i < 1000; i++)
{
mk.WaitOne();
mk.Reset(); // 把这行去掉会咋样?
for (int j = 0; j < 30; j++)
{
Console.Write(">");
Thread.Sleep(100);
}
mk.Set();
Thread.Sleep(500);
}
}
}
AutoResetEvent 和 ManualResetEvent 是 EventWaitHandle 的子类,功能都差不多,就不多说了。
(本系列完)
- 白话并发冲突与线程同步(3)——Mutex、EventWaitHandle、AutoResetEvent 和 ManualResetEvent
- 白话并发冲突与线程同步(3)——Mutex、EventWaitHandle、AutoResetEvent 和 ManualResetEvent
- 白话并发冲突与线程同步(3)——Mutex、EventWaitHandle、AutoResetEvent 和 Manua (2012-05-18 13:16:12)
- 基元线程同步——内核模式构造(WaitHandle,EventWaitHandle,AutoResetEvent,ManualResetEvent,Semaphore,Mutex)
- 线程同步 - EventWaitHandle & AutoResetEvent & ManualResetEvent
- AutoResetEvent和ManualResetEvent 线程同步
- 线程同步:ManualResetEvent和AutoResetEvent
- 白话并发冲突与线程同步(2)——Monitor、lock和死锁
- 白话并发冲突与线程同步(2)——Monitor、lock和死锁
- 白话并发冲突与线程同步(2)——Monitor、lock和死锁
- 白话并发冲突与线程同步(2)——Monitor、lock和死锁
- 白话并发冲突与线程同步(2)——Monitor、lock和死锁
- .Net下的线程同步:Part 1 of N--(EventWaitHandle:AutoResetEvent and ManualResetEvent)
- 白话并发冲突与线程同步(1)
- 白话并发冲突与线程同步(1)
- 白话并发冲突与线程同步(1)
- ManualResetEvent,AutoResetEvent类线程同步
- 多线程之线程同步中的信号量AutoResetEvent和ManualResetEvent
- XSLT学习笔记--NET Framework对XSLT的支持(2)
- 请帮忙。。。 使用谷歌代码网站上的开源代码,为指定站点提供AJAX定制搜索
- XSLT学习笔记--NET Framework对XSLT的支持(1)
- 正在学习ajax
- 第一次!做博客
- 白话并发冲突与线程同步(3)——Mutex、EventWaitHandle、AutoResetEvent 和 ManualResetEvent
- (转)关于pipe()的详细解析
- 白话并发冲突与线程同步(2)——Monitor、lock和死锁
- webservices与AJAX
- 中国导航的前景
- 白话并发冲突与线程同步(1)
- Textarea自动适用高度且无滚动条解决方案
- 接触Flex Builder
- 修改SQL排序准则