随笔 - 60  文章 - 24 评论 - 1560 trackbacks - 29

.net asp web c# vb VS2005 VS2008 VS2003

    姓名 景春雷
    网名 1-2-3
    生日 1980.2.29
    城市 沈阳
[生活]昨晚看了变形金刚2。场面火爆,观众也火爆,居然买不到7:30的票,只好等9:30那场。PS:高中以后就没去过电影院了。

与我联系

搜索

 

常用链接

我参与的团队

我的标签

随笔分类(59)

随笔档案(57)

文章分类(23)

相册

收藏夹(2)

积分与排名

  • 积分 - 207375
  • 排名 - 223

最新评论

阅读排行榜

评论排行榜

     不过这热气是从实在的火里发出来的呢,还是从他的爱情里发出来的呢,他完全不知道。他的一切光彩现在都没有了。这是因为他在旅途中失去了呢,还是悲愁的结果,谁也说不出来。
                                                                                    ——安徒生
                                                                                          摘自《坚定的锡兵》
摘要

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);
        }
    }
}

接连运行此程序的两个实例,把它们并排排放在一起(如下图所示),即可看到箭头从左边的窗体“穿越”到右边窗体的效果了。


是的,我们需要同步两个进程(中的主线程),这个工作需要交给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);
        }
    }
}



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(1003000));
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

2) ManualReset

AutoResetEvent 和 ManualResetEvent 是 EventWaitHandle 的子类,功能都差不多,就不多说了。

(本系列完)



posted on 2008-06-10 08:21 1-2-3 阅读(3099) 评论(35)  编辑 收藏 网摘 所属分类: 白话线程同步系列

FeedBack:
#1楼 2008-06-10 08:31 allies[未注册用户]
楼主找的图不错...
  回复  引用    
#2楼 2008-06-10 08:32 阿弱[未注册用户]
我们都曾是坚定的锡兵,走过光荣的荆棘路。
  回复  引用    
#3楼[楼主] 2008-06-10 08:36 1-2-3      
@阿弱
http://www.cnblogs.com/Emoticons/qface/055242240.gif" alt="" />

  回复  引用  查看    
mk 的比喻很形象
  回复  引用  查看    
#5楼 2008-06-10 08:42 非空      
大早占沙发!怎么就系列完了呢 还没看过瘾那~~~
  回复  引用  查看    
#6楼 2008-06-10 09:10 Zigzag      
很好,很强大。^_^
  回复  引用  查看    
#7楼 2008-06-10 09:18 lazylu      
真精彩啊~~在园子里面极少这么有灵感的文章~~~
  回复  引用  查看    
#8楼 2008-06-10 09:34 成长的强强      
很喜欢楼主的文章!!!
  回复  引用  查看    
#9楼 2008-06-10 09:46 JesseZhao      
图很好啊
  回复  引用  查看    
#10楼 2008-06-10 09:54 John Rambo      
学习同步,用厕所做例子确实再恰当不过了。
  回复  引用  查看    
#11楼 2008-06-10 11:49 王计平      
比喻很形象。
我喜欢有恰当比喻的文章,有幽默的比喻更好,有龌龊的比喻最好。

  回复  引用  查看    
#12楼[楼主] 2008-06-10 12:24 1-2-3      
@allies
@木野狐(Neil Chen)
@非空
@Zigzag
@lazylu
@成长的强强
@JesseZhao
@John Rambo
@王计平
谢谢。唉,以后要忙了,不知还有没有时间写。

  回复  引用  查看    
#14楼 2008-06-10 12:30 BlueMountain      
ls注意了

WaitAll~~~~~~~~~~~~~~~

  回复  引用  查看    
#15楼[楼主] 2008-06-10 12:56 1-2-3      
@zzz
非常好,正在看。

  回复  引用  查看    
#16楼 2008-06-10 13:24 体彩[未注册用户]
学习了,转载了!!!打声招呼,嘿嘿,就不叫偷了!!!
  回复  引用    
#17楼 2008-06-10 14:10 rr[未注册用户]
我把LZ这类文章和我的小说放一起

看起来幽默而富有风趣且不失内涵

  回复  引用    
#18楼[楼主] 2008-06-10 14:21 1-2-3      
@体彩
欢迎转载。

  回复  引用  查看    
#19楼[楼主] 2008-06-10 14:21 1-2-3      
@rr
谢谢夸奖。

  回复  引用  查看    
#20楼 2008-06-10 17:22 怪虎      
楼主是块不错的老师料子。
  回复  引用  查看    
#21楼 2008-06-10 17:23 airwolf2026      
mark 20
--------
mark 21le ...

  回复  引用  查看    
同志,你做得很好
  回复  引用    
呵呵, 看到眼熟的东西了


123, 最近怎么样啊 ?

  回复  引用  查看    
哈哈,博主真是有意思,文字也幽默!
  回复  引用    
#25楼[楼主] 2008-06-11 08:58 1-2-3      
@G yc {Son of VB.NET}
唉,凑合混呗。

  回复  引用  查看    
#26楼 2008-06-11 14:01 随风流月      
请问有没有办法把占着茅坑的那位强行从茅坑上驱逐下来?
  回复  引用  查看    
#27楼[楼主] 2008-06-11 17:49 1-2-3      
@随风流月
这个我可不知道。只知道有个TryEnter()函数,可以设置最多等多少秒超时就不等了。

  回复  引用  查看    
#28楼 2008-08-17 12:54 包建强      
lz还是遗漏了很多同步技术的:
比如说Monitor.Wait()和Monitor.Pulse()的几种玩法;
比如说读写锁、受保护的挂起、阻行、双缓冲、调度器、Future、生产/消费者;
比如说多线程的三种关系:主从、平行、顺序;
此外,手动控制只讲了Mutex原语,没说明白Interlock、AutoResetEvent、ManualResetEvent几个小玩意。
还有就是同步上下文技术:SynchronizationAttribute。

以上这些都说明白了,再加上楼主的这个系列,同步技术就完美了。

  回复  引用  查看    
#29楼 2008-08-17 13:29 包建强      
还有,你这个系列会误导大家以为并发只要处理对象锁定就可以了,而忽略了同步的另一个重要方面,那就是线程的顺序。为此我们需要建立调度器Schedule,才能控制先进先出。
  回复  引用  查看    
#30楼[楼主] 2008-08-18 08:29 1-2-3      
@包建强
非常感谢你的提醒。上面所说的这些东西在哪里可以学到呢?

  回复  引用  查看    
#31楼 2008-10-21 13:17 huangxq[未注册用户]
lock关键字如何用?
我看有以下各种不同的用法,他们有什么区别呢?
lock(this);
lock(typeof(xxxx));
lock(object);
lock(静态变量);

  回复  引用    
#32楼[楼主] 2008-10-21 16:52 1-2-3      
@huangxq
如果有若干线程都lock()了同一个object,那么同一时刻只有其中的一个线程处于运行状态,其它线程会处于等待状态。
所以lock的那个object要选得恰当。
理想的情况是被lock的那个object最好是只有需要同步的那几个线程才能访问,这样可以防止出现恰巧有别的你所不知道的线程也lock了它的情况。
所以一般情况下不要使用lock(typeof(xxxx));或lock(共有静态变量);,因为它们的生命周期嗷嗷长,可访问范围嗷嗷大,非常容易出现大家都去lock它们的情况。

  回复  引用  查看    
@1-2-3,
老兄加我MSN,我的MSN在我首页的左边头像的下方

  回复  引用    
好文!赞!
  回复  引用    
#35楼[楼主] 2008-11-07 17:02 1-2-3      
@路人中的路人
谢谢。每次看到“路人”、“路过”之类的字眼,都会感叹这世界太大啦!99.9999%的人我都不认识,这真叫人惆怅!若是个傻瓜男人也就罢了,若是个美女,匆匆一睥之后就不见了踪影,怎能不叫人唏嘘!

  回复  引用  查看    



发表评论

昵称: [登录] [注册]

主页:

邮箱:(仅博主可见)

评论内容:

  登录  注册

[使用Ctrl+Enter键快速提交评论]

0 1212391




相关文章:

相关链接: