ManualResetEvent, AutoResetEvent,和EventWaitHandle线程交互

阅读更多

 

ManualResetEvent ,AutoResetEvent 都可以阻塞线程执行,直到收到set()信号,线程被释放。

ManualResetEvent 和AutoResetEvent不同点是 前者需要手动调用Reset()重置,才会继续去阻塞线程,

后者是自动被Reset();所以针对多个线程被阻塞时,ManualResetEvent 调用一次Set() 即可释放所有线程。

AutoResetEvent由于自动被重置了,所以每个线程都需要调用一次Set() 才能被释放。

 

 

如下实例定义多个线程:

using System;
using System.Threading;

public class Example
{
    // mre手动阻塞和释放线程. 构造参数initalState为初始状态,false为无信号状态(遇到WaitOne方法,会阻塞)
    // true为有信号状态(遇到WaitOne方法,会直接执行)
    private static ManualResetEvent mre = new ManualResetEvent(false);

    static void Main()
    {
        Console.WriteLine("\nStart 3 named threads that block on a ManualResetEvent:\n");

        for (int i = 0; i <= 2; i++)
        {
            Thread t = new Thread(ThreadProc);
            t.Name = "Thread_" + i;
            t.Start();
        }

        Thread.Sleep(500);
        Console.WriteLine("\nWhen all three threads have started, press Enter to call Set()" +
                          "\nto release all the threads.\n");
        Console.ReadLine();
        //设置状态,允许一个或多个线程从阻塞状态继续执行,这时被阻塞的线程会全部执行。
        mre.Set();

        Thread.Sleep(500);
        Console.WriteLine("\nWhen a ManualResetEvent is signaled, threads that call WaitOne()" +
                          "\ndo not block. Press Enter to show this.\n");
        Console.ReadLine();
        //这里的两个线程中的WaitOne()是不会阻塞的,因为这个时候没有重置状态,此时的状态还是true
        for (int i = 3; i <= 4; i++)
        {
            Thread t = new Thread(ThreadProc);
            t.Name = "Thread_" + i;
            t.Start();
        }

        Thread.Sleep(500);
        Console.WriteLine("\nPress Enter to call Reset(), so that threads once again block" +
                          "\nwhen they call WaitOne().\n");
        Console.ReadLine();
        //重置状态,此时下面的线程5 遇到WaitOne()会阻塞
        mre.Reset();

        // Start a thread that waits on the ManualResetEvent.
        Thread t5 = new Thread(ThreadProc);
        t5.Name = "Thread_5";
        t5.Start();

        Thread.Sleep(500);
        Console.WriteLine("\nPress Enter to call Set() and conclude the demo.");
        Console.ReadLine();

        mre.Set();

        // If you run this example in Visual Studio, uncomment the following line:
        //Console.ReadLine();
    }


    private static void ThreadProc()
    {
        string name = Thread.CurrentThread.Name;

        Console.WriteLine(name + " starts and calls mre.WaitOne()");
        //阻塞线程往下执行
        mre.WaitOne();

        Console.WriteLine(name + " ends.");
    }
}

/* This example produces output similar to the following:

Start 3 named threads that block on a ManualResetEvent:

Thread_0 starts and calls mre.WaitOne()
Thread_1 starts and calls mre.WaitOne()
Thread_2 starts and calls mre.WaitOne()

When all three threads have started, press Enter to call Set()
to release all the threads.


Thread_2 ends.
Thread_0 ends.
Thread_1 ends.

When a ManualResetEvent is signaled, threads that call WaitOne()
do not block. Press Enter to show this.


Thread_3 starts and calls mre.WaitOne()
Thread_3 ends.
Thread_4 starts and calls mre.WaitOne()
Thread_4 ends.

Press Enter to call Reset(), so that threads once again block
when they call WaitOne().


Thread_5 starts and calls mre.WaitOne()

Press Enter to call Set() and conclude the demo.

Thread_5 ends.
 */

 

using System;
using System.Threading;

// AutoResetEvent 自动重置信号进行阻塞,
//   当设置Set()后会自动重置成false状态进行阻塞。
class Example
{
    //true 信号,表示现在的状态为非阻塞状态,
    //第一个到达线程,遇到第一个WaitOne()会直接通过,其它线程会被阻塞。
    private static AutoResetEvent event_1 = new AutoResetEvent(true);
    private static AutoResetEvent event_2 = new AutoResetEvent(false);

    static void Main()
    {
        Console.WriteLine("Press Enter to create three threads and start them.\r\n" +
                          "The threads wait on AutoResetEvent #1, which was created\r\n" +
                          "in the signaled state, so the first thread is released.\r\n" +
                          "This puts AutoResetEvent #1 into the unsignaled state.");
        Console.ReadLine();

        for (int i = 1; i < 4; i++)
        {
            Thread t = new Thread(ThreadProc);
            t.Name = "Thread_" + i;
            t.Start();
        }
        Thread.Sleep(250);
        //event_1初始值为true,所以这里这里只需要对剩下的两个线程进行Set()
        for (int i = 0; i < 2; i++)
        {
            Console.WriteLine("Press Enter to release another thread.");
            Console.ReadLine();
            event_1.Set();
            Thread.Sleep(250);
        }


        Console.WriteLine("\r\nAll threads are now waiting on AutoResetEvent #2.");
        //event_2初始状态为false 所以三个线程需要三次被释放。
        for (int i = 0; i < 3; i++)
        {
            Console.WriteLine("Press Enter to release a thread.");
            Console.ReadLine();
            event_2.Set();
            Thread.Sleep(250);
        }

        // Visual Studio: Uncomment the following line.
        //Console.Readline();
    }

    static void ThreadProc()
    {
        string name = Thread.CurrentThread.Name;

        Console.WriteLine("{0} waits on AutoResetEvent #1.", name);
        //由于event_1信号初始为true,所以第一个到达线程会直接通过。随即信号被自动重置为了false。
        //其他线程被阻塞,当调用Set()方法的时候,当前线程会通过,随机又会自动重置为false,
        //每个线程需要执行一次Set().
        //与ManualResetEvent 不同的是,ManualResetEvent 需要手工设置Reset(),所以在手工没有重置之前,所有线程都会被释放。
        //AutoResetEvent自动重置,每个线程都需要被Set()才能被释放。
        event_1.WaitOne();
        Console.WriteLine("{0} is released from AutoResetEvent #1.", name);

        Console.WriteLine("{0} waits on AutoResetEvent #2.", name);
        event_2.WaitOne();
        Console.WriteLine("{0} is released from AutoResetEvent #2.", name);

        Console.WriteLine("{0} ends.", name);
    }
}

/* This example produces output similar to the following:

Press Enter to create three threads and start them.
The threads wait on AutoResetEvent #1, which was created
in the signaled state, so the first thread is released.
This puts AutoResetEvent #1 into the unsignaled state.

Thread_1 waits on AutoResetEvent #1.
Thread_1 is released from AutoResetEvent #1.
Thread_1 waits on AutoResetEvent #2.
Thread_3 waits on AutoResetEvent #1.
Thread_2 waits on AutoResetEvent #1.
Press Enter to release another thread.

Thread_3 is released from AutoResetEvent #1.
Thread_3 waits on AutoResetEvent #2.
Press Enter to release another thread.

Thread_2 is released from AutoResetEvent #1.
Thread_2 waits on AutoResetEvent #2.

All threads are now waiting on AutoResetEvent #2.
Press Enter to release a thread.

Thread_2 is released from AutoResetEvent #2.
Thread_2 ends.
Press Enter to release a thread.

Thread_1 is released from AutoResetEvent #2.
Thread_1 ends.
Press Enter to release a thread.

Thread_3 is released from AutoResetEvent #2.
Thread_3 ends.
 */

 

 

EventWaitHandle

线程阻塞事件 定义如下

EventWaitHandle clearCount =  new EventWaitHandle(false, EventResetMode.AutoReset);

using System;
using System.Threading;

public class Example
{
    // EventWaitHandle 用于演示
    //  AutoReset 和 ManualReset 同步事件
    //
    private static EventWaitHandle ewh;

    //一个计数器,用于确保所有线程都已启动并且
    //在释放之前被阻止。 A Long用于显示
    //使用64位Interlocked方法。
    private static long threadCount = 0;

    // An AutoReset event that allows the main thread to block
    // until an exiting thread has decremented the count.
    //阻塞主线程执行,while循环中的 WaitHandle.SignalAndWait(ewh, clearCount);释放ewh,阻塞clearCount
    private static EventWaitHandle clearCount =
        new EventWaitHandle(false, EventResetMode.AutoReset);

    [MTAThread]
    public static void Main()
    {
        // Create an AutoReset EventWaitHandle.
        //
        ewh = new EventWaitHandle(false, EventResetMode.AutoReset);

        // 创建5个线程. 使用
        // ParameterizedThreadStart 委托, 能传线程索引参数到start方法
        // 
        for (int i = 0; i <= 4; i++)
        {
            Thread t = new Thread(
                new ParameterizedThreadStart(ThreadProc)
            );
            t.Start(i);
        }

        //等待所有线程都已启动并阻止。
        //当多个线程在32位上使用64位值时
        //系统,你必须通过访问该值
        //互锁类以保证线程安全。
        //
        while (Interlocked.Read(ref threadCount) < 5)
        {
            Thread.Sleep(500);
        }

        // Release one thread each time the user presses ENTER,
        // until all threads have been released.
        //
        while (Interlocked.Read(ref threadCount) > 0)
        {
            Console.WriteLine("Press ENTER to release a waiting thread.");
            Console.ReadLine();

            // SignalAndWait发出EventWaitHandle信号
            //在重置之前正好释放一个线程,
            //因为它是使用AutoReset模式创建的。
            // SignalAndWait然后在clearCount上阻塞。
            //再循环之前,允许发出信号的线程减少计数
            //
            WaitHandle.SignalAndWait(ewh, clearCount);
        }
        Console.WriteLine();

        // 创建一个 ManualReset EventWaitHandle.
        //
        ewh = new EventWaitHandle(false, EventResetMode.ManualReset);

        // Create and start five more numbered threads.
        //
        for (int i = 0; i <= 4; i++)
        {
            Thread t = new Thread(
                new ParameterizedThreadStart(ThreadProc)
            );
            t.Start(i);
        }

        // Wait until all the threads have started and blocked.
        //
        while (Interlocked.Read(ref threadCount) < 5)
        {
            Thread.Sleep(500);
        }

        //因为EventWaitHandle是
        // ManualReset模式创建的,
        //发出信号释放所有等待线程。
        //
        Console.WriteLine("Press ENTER to release the waiting threads.");
        Console.ReadLine();
        ewh.Set();

    }

    public static void ThreadProc(object data)
    {
        int index = (int)data;

        Console.WriteLine("Thread {0} blocks.", data);
        // 增加阻塞线程数.
        Interlocked.Increment(ref threadCount);

        // 阻塞
        ewh.WaitOne();

        Console.WriteLine("Thread {0} exits.", data);
        //减少阻塞线程数
        Interlocked.Decrement(ref threadCount);

        //在发送ewh信号后,主线程阻塞
        // clearCount直到发出信号的线程有
        //递减计数 立即发信号。
        //
        clearCount.Set();
    }
}

 

 

你可能感兴趣的:(AutoResetEvent)