C#并发冲突与线程同步(3)——Mutex,EventWaitHandle,AutoResetEvent

Mutex的WaitOne()函数 >çÉYûùWfwww.netcsharp.cnS&4~ÅeĪÿi
>çÉYûùWfwww.netcsharp.cnS&4~ÅeĪÿi
前几天1-2-3去黑木崖找东方不败玩,听到东方不败抱怨说整天绣花眼睛好累呀,于是1-2-3就给东方不败编了一个活动眼睛的程序。 >çÉYûùWfwww.netcsharp.cnS&4~ÅeĪÿi
>çÉYûùWfwww.netcsharp.cnS&4~ÅeĪÿi
class Program>çÉYûùWfwww.netcsharp.cnS&4~ÅeĪÿi
{>çÉYûùWfwww.netcsharp.cnS&4~ÅeĪÿi
    static void Main(string[] args)>çÉYûùWfwww.netcsharp.cnS&4~ÅeĪÿi
    {>çÉYûùWfwww.netcsharp.cnS&4~ÅeĪÿi
        // 为截图方便把窗体设小一点>çÉYûùWfwww.netcsharp.cnS&4~ÅeĪÿi
        Console.WindowWidth = 30; Console.BufferWidth = 30; >çÉYûùWfwww.netcsharp.cnS&4~ÅeĪÿi
        Console.WindowHeight = 16; Console.BufferHeight = 16;>çÉYûùWfwww.netcsharp.cnS&4~ÅeĪÿi
        >çÉYûùWfwww.netcsharp.cnS&4~ÅeĪÿi
        Mutex mk = new Mutex(false, "my mutex");>çÉYûùWfwww.netcsharp.cnS&4~ÅeĪÿi
        for (int i = 0; i < 1000; i++)>çÉYûùWfwww.netcsharp.cnS&4~ÅeĪÿi
        {>çÉYûùWfwww.netcsharp.cnS&4~ÅeĪÿi
            mk.WaitOne();>çÉYûùWfwww.netcsharp.cnS&4~ÅeĪÿi
            for (int j = 0; j < 30; j++)>çÉYûùWfwww.netcsharp.cnS&4~ÅeĪÿi
            {>çÉYûùWfwww.netcsharp.cnS&4~ÅeĪÿi
                Console.Write(">");>çÉYûùWfwww.netcsharp.cnS&4~ÅeĪÿi
                Thread.Sleep(100);>çÉYûùWfwww.netcsharp.cnS&4~ÅeĪÿi
            }>çÉYûùWfwww.netcsharp.cnS&4~ÅeĪÿi
            mk.ReleaseMutex();>çÉYûùWfwww.netcsharp.cnS&4~ÅeĪÿi
            Thread.Sleep(500);>çÉYûùWfwww.netcsharp.cnS&4~ÅeĪÿi
        }>çÉYûùWfwww.netcsharp.cnS&4~ÅeĪÿi
    }>çÉYûùWfwww.netcsharp.cnS&4~ÅeĪÿi
}>çÉYûùWfwww.netcsharp.cnS&4~ÅeĪÿi
>çÉYûùWfwww.netcsharp.cnS&4~ÅeĪÿi
>çÉYûùWfwww.netcsharp.cnS&4~ÅeĪÿi
接连运行此程序的两个实例,把它们并排排放在一起(如下图所示),即可看到箭头从左边的窗体“穿越”到右边窗体的效果了。 >çÉYûùWfwww.netcsharp.cnS&4~ÅeĪÿi
>çÉYûùWfwww.netcsharp.cnS&4~ÅeĪÿi
>çÉYûùWfwww.netcsharp.cnS&4~ÅeĪÿi
是 的,我们需要同步两个进程(中的主线程),这个工作需要交给Mutex。Mutex和Monitor的概念十分相似,只不过Monitor是.net内建 的线程同步机制,Mutex是封装了Windows操作系统的线程同步机制;Monitor速度快,Mutex的速度要比Monitor慢很多; Monitor只能用于同步同一进程内的线程;Mutex则可以用于同步隶属于不同进程的线程。 >çÉYûùWfwww.netcsharp.cnS&4~ÅeĪÿi
>çÉYûùWfwww.netcsharp.cnS&4~ÅeĪÿi
Mutex的WaitAll()函数 >çÉYûùWfwww.netcsharp.cnS&4~ÅeĪÿi
>çÉYûùWfwww.netcsharp.cnS&4~ÅeĪÿi
现在我们对WC进行了扩建,把mk增加到两个,可是却遇到了两个讲排场的进程,它们都要同时占两个mk才肯办事,所以运行起来的效果和前一个程序一样。 >çÉYûùWfwww.netcsharp.cnS&4~ÅeĪÿi
class Program >çÉYûùWfwww.netcsharp.cnS&4~ÅeĪÿi
{ >çÉYûùWfwww.netcsharp.cnS&4~ÅeĪÿi
    static void Main(string[] args) >çÉYûùWfwww.netcsharp.cnS&4~ÅeĪÿi
    { >çÉYûùWfwww.netcsharp.cnS&4~ÅeĪÿi
        // 为截图方便把窗体设小一点 >çÉYûùWfwww.netcsharp.cnS&4~ÅeĪÿi
        Console.WindowWidth = 30; Console.BufferWidth = 30; >çÉYûùWfwww.netcsharp.cnS&4~ÅeĪÿi
        Console.WindowHeight = 16; Console.BufferHeight = 16; >çÉYûùWfwww.netcsharp.cnS&4~ÅeĪÿi
        >çÉYûùWfwww.netcsharp.cnS&4~ÅeĪÿi
        Mutex mk1 = new Mutex(false, "my mutex1"); >çÉYûùWfwww.netcsharp.cnS&4~ÅeĪÿi
        Mutex mk2 = new Mutex(false, "my mutex2"); >çÉYûùWfwww.netcsharp.cnS&4~ÅeĪÿi
        Mutex[] mks = new Mutex[] { mk1, mk2 }; >çÉYûùWfwww.netcsharp.cnS&4~ÅeĪÿi
>çÉYûùWfwww.netcsharp.cnS&4~ÅeĪÿi
        for (int i = 0; i < 1000; i++) >çÉYûùWfwww.netcsharp.cnS&4~ÅeĪÿi
        { >çÉYûùWfwww.netcsharp.cnS&4~ÅeĪÿi
            Mutex.WaitAll(mks); >çÉYûùWfwww.netcsharp.cnS&4~ÅeĪÿi
            for (int j = 0; j < 30; j++) >çÉYûùWfwww.netcsharp.cnS&4~ÅeĪÿi
            { >çÉYûùWfwww.netcsharp.cnS&4~ÅeĪÿi
                Console.Write(">"); >çÉYûùWfwww.netcsharp.cnS&4~ÅeĪÿi
                Thread.Sleep(100); >çÉYûùWfwww.netcsharp.cnS&4~ÅeĪÿi
            } >çÉYûùWfwww.netcsharp.cnS&4~ÅeĪÿi
>çÉYûùWfwww.netcsharp.cnS&4~ÅeĪÿi
            mk1.ReleaseMutex(); >çÉYûùWfwww.netcsharp.cnS&4~ÅeĪÿi
            mk2.ReleaseMutex(); >çÉYûùWfwww.netcsharp.cnS&4~ÅeĪÿi
            Thread.Sleep(500); >çÉYûùWfwww.netcsharp.cnS&4~ÅeĪÿi
        } >çÉYûùWfwww.netcsharp.cnS&4~ÅeĪÿi
    } >çÉYûùWfwww.netcsharp.cnS&4~ÅeĪÿi
} >çÉYûùWfwww.netcsharp.cnS&4~ÅeĪÿi
>çÉYûùWfwww.netcsharp.cnS&4~ÅeĪÿi
C#并发冲突与线程同步(3)——Mutex,EventWaitHandle,AutoResetEvent_第1张图片 >çÉYûùWfwww.netcsharp.cnS&4~ÅeĪÿi
>çÉYûùWfwww.netcsharp.cnS&4~ÅeĪÿi
Mutex的WaitAny()函数 >çÉYûùWfwww.netcsharp.cnS&4~ÅeĪÿi
>çÉYûùWfwww.netcsharp.cnS&4~ÅeĪÿi
看下这个小程序 >çÉYûùWfwww.netcsharp.cnS&4~ÅeĪÿi
1 class Program >çÉYûùWfwww.netcsharp.cnS&4~ÅeĪÿi
2 { >çÉYûùWfwww.netcsharp.cnS&4~ÅeĪÿi
3    static void Main(string[] args) >çÉYûùWfwww.netcsharp.cnS&4~ÅeĪÿi
4     { >çÉYûùWfwww.netcsharp.cnS&4~ÅeĪÿi
5        // 为截图方便把窗体设小一点 >çÉYûùWfwww.netcsharp.cnS&4~ÅeĪÿi
6         Console.WindowWidth = 30; Console.BufferWidth = 30; >çÉYûùWfwww.netcsharp.cnS&4~ÅeĪÿi
7         Console.WindowHeight = 16; Console.BufferHeight = 16; >çÉYûùWfwww.netcsharp.cnS&4~ÅeĪÿi
8         >çÉYûùWfwww.netcsharp.cnS&4~ÅeĪÿi
9         Mutex mk1 = new Mutex(false, "my mutex1"); >çÉYûùWfwww.netcsharp.cnS&4~ÅeĪÿi
10         Mutex mk2 = new Mutex(false, "my mutex2"); >çÉYûùWfwww.netcsharp.cnS&4~ÅeĪÿi
11         Mutex[] mks = new Mutex[] { mk1, mk2 }; >çÉYûùWfwww.netcsharp.cnS&4~ÅeĪÿi
12 >çÉYûùWfwww.netcsharp.cnS&4~ÅeĪÿi
13        for (int i = 0; i < 1000; i++) >çÉYûùWfwww.netcsharp.cnS&4~ÅeĪÿi
14         { >çÉYûùWfwww.netcsharp.cnS&4~ÅeĪÿi
15            int index = Mutex.WaitAny(mks); // 返回值为此进程占用的mk在mks里的index >çÉYûùWfwww.netcsharp.cnS&4~ÅeĪÿi
16             Console.Write("Index: " + index.ToString()); >çÉYûùWfwww.netcsharp.cnS&4~ÅeĪÿi
17            for (int j = 0; j < 30; j++) >çÉYûùWfwww.netcsharp.cnS&4~ÅeĪÿi
18             { >çÉYûùWfwww.netcsharp.cnS&4~ÅeĪÿi
19                 Console.Write(">"); >çÉYûùWfwww.netcsharp.cnS&4~ÅeĪÿi
20                 Thread.Sleep(100); >çÉYûùWfwww.netcsharp.cnS&4~ÅeĪÿi
21             } >çÉYûùWfwww.netcsharp.cnS&4~ÅeĪÿi
22 >çÉYûùWfwww.netcsharp.cnS&4~ÅeĪÿi
23             mks[index].ReleaseMutex(); >çÉYûùWfwww.netcsharp.cnS&4~ÅeĪÿi
24             Thread.Sleep(new Random().Next(100, 3000)); >çÉYûùWfwww.netcsharp.cnS&4~ÅeĪÿi
25         } >çÉYûùWfwww.netcsharp.cnS&4~ÅeĪÿi
26     } >çÉYûùWfwww.netcsharp.cnS&4~ÅeĪÿi
27 } >çÉYûùWfwww.netcsharp.cnS&4~ÅeĪÿi
>çÉYûùWfwww.netcsharp.cnS&4~ÅeĪÿi
如 果同时运行此程序的两个实例,正如本文摘要里所写的,只要mk1和mk2有一个是空闲的,进程就可以进去办事,所以两个进程可以同时输出">"字 符。注意程序的第24行,每个进程在输出30个">"字符后都会随机Sleep 100到3000毫秒,这样就有可能出现mk1和mk2同时空闲的情况,所以就会出现一会儿进程1占用mk1而进程2占用mk2;一会儿进程1占用mk2 而进程2占用mk1的情况(在下图分别用绿色和红色波浪线标出)。 >çÉYûùWfwww.netcsharp.cnS&4~ÅeĪÿi
C#并发冲突与线程同步(3)——Mutex,EventWaitHandle,AutoResetEvent_第2张图片 >çÉYûùWfwww.netcsharp.cnS&4~ÅeĪÿi
>çÉYûùWfwww.netcsharp.cnS&4~ÅeĪÿi
EventWaitHandle、AutoResetEvent 和 ManualResetEvent >çÉYûùWfwww.netcsharp.cnS&4~ÅeĪÿi
>çÉYûùWfwww.netcsharp.cnS&4~ÅeĪÿi
EventWaitHandle的名字与Mutex差了很多,不过它可是Mutex不折不扣的兄弟——它和Mutex都是WaitHandle的子类,用法也差不多。下面这两段程序实现了与本文的第一段程序相同的功能。 >çÉYûùWfwww.netcsharp.cnS&4~ÅeĪÿi
1) AutoReset >çÉYûùWfwww.netcsharp.cnS&4~ÅeĪÿi
class Program >çÉYûùWfwww.netcsharp.cnS&4~ÅeĪÿi
{ >çÉYûùWfwww.netcsharp.cnS&4~ÅeĪÿi
    static void Main(string[] args) >çÉYûùWfwww.netcsharp.cnS&4~ÅeĪÿi
    { >çÉYûùWfwww.netcsharp.cnS&4~ÅeĪÿi
        // 为截图方便把窗体设小一点 >çÉYûùWfwww.netcsharp.cnS&4~ÅeĪÿi
        Console.WindowWidth = 30; Console.BufferWidth = 30; >çÉYûùWfwww.netcsharp.cnS&4~ÅeĪÿi
        Console.WindowHeight = 16; Console.BufferHeight = 16; >çÉYûùWfwww.netcsharp.cnS&4~ÅeĪÿi
>çÉYûùWfwww.netcsharp.cnS&4~ÅeĪÿi
        EventWaitHandle mk = new EventWaitHandle(true, EventResetMode.AutoReset, "my mk"); >çÉYûùWfwww.netcsharp.cnS&4~ÅeĪÿi
        >çÉYûùWfwww.netcsharp.cnS&4~ÅeĪÿi
        for (int i = 0; i < 1000; i++) >çÉYûùWfwww.netcsharp.cnS&4~ÅeĪÿi
        { >çÉYûùWfwww.netcsharp.cnS&4~ÅeĪÿi
            mk.WaitOne(); >çÉYûùWfwww.netcsharp.cnS&4~ÅeĪÿi
            for (int j = 0; j < 30; j++) >çÉYûùWfwww.netcsharp.cnS&4~ÅeĪÿi
            { >çÉYûùWfwww.netcsharp.cnS&4~ÅeĪÿi
                Console.Write(">"); >çÉYûùWfwww.netcsharp.cnS&4~ÅeĪÿi
                Thread.Sleep(100); >çÉYûùWfwww.netcsharp.cnS&4~ÅeĪÿi
            } >çÉYûùWfwww.netcsharp.cnS&4~ÅeĪÿi
            mk.Set(); >çÉYûùWfwww.netcsharp.cnS&4~ÅeĪÿi
            Thread.Sleep(500); >çÉYûùWfwww.netcsharp.cnS&4~ÅeĪÿi
        } >çÉYûùWfwww.netcsharp.cnS&4~ÅeĪÿi
    } >çÉYûùWfwww.netcsharp.cnS&4~ÅeĪÿi
} >çÉYûùWfwww.netcsharp.cnS&4~ÅeĪÿi
>çÉYûùWfwww.netcsharp.cnS&4~ÅeĪÿi
2) ManualReset >çÉYûùWfwww.netcsharp.cnS&4~ÅeĪÿi
class Program >çÉYûùWfwww.netcsharp.cnS&4~ÅeĪÿi
{ >çÉYûùWfwww.netcsharp.cnS&4~ÅeĪÿi
    static void Main(string[] args) >çÉYûùWfwww.netcsharp.cnS&4~ÅeĪÿi
    { >çÉYûùWfwww.netcsharp.cnS&4~ÅeĪÿi
        // 为截图方便把窗体设小一点 >çÉYûùWfwww.netcsharp.cnS&4~ÅeĪÿi
        Console.WindowWidth = 30; Console.BufferWidth = 30; >çÉYûùWfwww.netcsharp.cnS&4~ÅeĪÿi
        Console.WindowHeight = 16; Console.BufferHeight = 16; >çÉYûùWfwww.netcsharp.cnS&4~ÅeĪÿi
>çÉYûùWfwww.netcsharp.cnS&4~ÅeĪÿi
        EventWaitHandle mk = new EventWaitHandle(true, EventResetMode.ManualReset, "my mk"); >çÉYûùWfwww.netcsharp.cnS&4~ÅeĪÿi
        >çÉYûùWfwww.netcsharp.cnS&4~ÅeĪÿi
        for (int i = 0; i < 1000; i++) >çÉYûùWfwww.netcsharp.cnS&4~ÅeĪÿi
        { >çÉYûùWfwww.netcsharp.cnS&4~ÅeĪÿi
            mk.WaitOne(); >çÉYûùWfwww.netcsharp.cnS&4~ÅeĪÿi
            mk.Reset();  // 把这行去掉会咋样? >çÉYûùWfwww.netcsharp.cnS&4~ÅeĪÿi
            for (int j = 0; j < 30; j++) >çÉYûùWfwww.netcsharp.cnS&4~ÅeĪÿi
            { >çÉYûùWfwww.netcsharp.cnS&4~ÅeĪÿi
                Console.Write(">"); >çÉYûùWfwww.netcsharp.cnS&4~ÅeĪÿi
                Thread.Sleep(100); >çÉYûùWfwww.netcsharp.cnS&4~ÅeĪÿi
            } >çÉYûùWfwww.netcsharp.cnS&4~ÅeĪÿi
            mk.Set(); >çÉYûùWfwww.netcsharp.cnS&4~ÅeĪÿi
            Thread.Sleep(500); >çÉYûùWfwww.netcsharp.cnS&4~ÅeĪÿi
        } >çÉYûùWfwww.netcsharp.cnS&4~ÅeĪÿi
    } >çÉYûùWfwww.netcsharp.cnS&4~ÅeĪÿi
} >çÉYûùWfwww.netcsharp.cnS&4~ÅeĪÿi
>çÉYûùWfwww.netcsharp.cnS&4~ÅeĪÿi
AutoResetEvent 和 ManualResetEvent 是 EventWaitHandle 的子类,功能都差不多,就不多说了

你可能感兴趣的:(C#并发冲突与线程同步(3)——Mutex,EventWaitHandle,AutoResetEvent)