`
wyf
  • 浏览: 437907 次
  • 性别: Icon_minigender_1
  • 来自: 唐山
社区版块
存档分类
最新评论

ManualResetEvent, AutoResetEvent,和EventWaitHandle线程交互

    博客分类:
  • C#
阅读更多

 

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

 

 

分享到:
评论

相关推荐

    C# 多线程同步、异步_AutoResetEvent用法

    总结,`AutoResetEvent`是C#中用于线程同步和异步控制的重要工具,它帮助开发者有效地管理线程间的交互,实现线程交替或跟随执行。在实际开发中,灵活运用这些概念和技术,可以提高程序的效率和并发性能。

    AutoResetEvent_Examples.zip_AutoResetEvent_ManualResetEvent

    在多线程编程中,`AutoResetEvent` 和 `ManualResetEvent` 是两种重要的同步原语,用于控制线程间的协作和同步。本压缩包文件提供了关于这两种事件类型的实例代码,帮助开发者理解它们的工作原理和用法。 首先,让...

    C#-【多线程篇】AutoResetEvent和ManualResetEvent的区别(中级)

    引入命名空间: using System.Threading; AutoResetEvent: autoResetEvent.WaitOne();//运行完后,**自动将事件...ManualResetEvent: manulResetEvent.WaitOne();//运行完后,**不会自动将事件状态设置为无信号**

    C#线程同步ManualResetEvent

    然而,多线程也带来了一定的复杂性,特别是在资源竞争和线程间协调方面。`ManualResetEvent`是.NET Framework提供的一种线程同步原语,用于控制线程的执行顺序和互斥访问,确保程序的正确性和一致性。 `...

    C# 多线程同步与互斥,使用Mutex和AutoResetEvent类

    - 分析和理解线程间的交互,确保没有竞态条件或死锁。 - 使用适当的同步机制,避免过度同步,提高性能。 - 注释清晰,特别是在不确定的地方,便于其他开发者理解和改进代码。 在提供的"multiThreading"文件夹中,...

    C#多线程编程实例 线程与窗体交互源码.rar

    - **信号量(ManualResetEvent, AutoResetEvent)**:用于线程间的同步,等待事件发生后才继续执行。 - **条件变量(Monitor.Wait, Monitor.Pulse)**:允许线程等待特定条件满足后才继续执行。 9. **线程状态** ...

    C# 如何挂起线程、休眠线程和终止线程(源码例)

    - **事件(Events)**:通过WaitHandle类的子类(如ManualResetEvent或AutoResetEvent)来同步线程,一个线程等待特定事件发生,另一个线程触发事件。 - **条件变量(Conditional Variables)**:允许线程在满足...

    ManualResetEvent最简单的测试代码

    在多线程编程中,`ManualResetEvent`是.NET Framework提供的一种同步原语,它用于控制线程间的通信和同步。这个类属于`System.Threading`命名空间,是`WaitHandle`的一个子类,用于创建一个可以手动重置的事件信号,...

    ManualResetEvent继续等待.rar

    总结来说,ManualResetEvent是.NET平台下实现线程同步的重要工具,通过其Set、Reset和WaitOne方法,我们可以精确控制线程的执行流程。了解并熟练运用这些方法,对于编写高效、稳定的多线程程序至关重要。同时,正确...

    C#多线程编程实例 线程与窗体交互源码

    5. **线程同步对象**:如`Mutex`, `Monitor`, `AutoResetEvent`, `ManualResetEvent`等,用于控制线程之间的访问和通信。 6. **线程状态管理**:了解`ThreadState`枚举,如`Running`, `Stopped`, `Aborted`等,以便...

    五个多线程同步应用小程序

    有两类EventWaitHandle:AutoResetEvent和ManualResetEvent。AutoResetEvent在事件触发后自动重置,只有一个等待的线程可以继续执行;而ManualResetEvent则需要手动调用Reset() 方法来重置事件状态,因此可以唤醒多...

    “线程”示例

    可以使用Monitor类的`Pulse()`和`Wait()`方法,或者使用ManualResetEvent和AutoResetEvent等事件对象。例如,一个线程可能需要等待另一个线程发出信号才能继续执行: ```csharp ManualResetEvent doneEvent = new ...

    带有消息机制的线程 - CustomMessageQueue

    同时,可以使用Thread的Sleep方法使线程在没有消息时进入等待状态,或者使用ManualResetEvent或AutoResetEvent来控制线程的启动和停止。 标签“c#”、“vb.net”表明这是两种.NET语言的实现,虽然语法和一些特性...

    .NET多线程编程教程,_NET多线程编程实例

    3.1 WaitOne/SignalOne:ManualResetEvent和AutoResetEvent用于线程间的等待和通知。 3.2 CountdownEvent:计数事件,当计数值减至零时,所有等待的线程被释放。 3.3 Barrier:屏障,使多个线程到达某一点后同时继续...

    C#-正确结束线程-通过给定信号结束线程.rar

    4. **WaitHandle.WaitOne() 和 WaitHandle.WaitAny():** 这两个方法允许线程等待一个或多个`WaitHandle`对象(如`ManualResetEvent`和`AutoResetEvent`)变为信号状态。在线程中,可以使用`WaitOne()`来阻塞线程,...

    多线程研究练习

    例如,`AutoResetEvent`和`ManualResetEvent`可以作为线程间的等待信号: ```csharp AutoResetEvent eventWaitHandle = new AutoResetEvent(false); // 等待信号 eventWaitHandle.WaitOne(); // 释放信号 ...

    ManualResetEvent的用法

    通过合理利用`ManualResetEvent`的状态转换,开发者可以构建复杂而高效的多线程应用程序,实现对资源的精确控制和线程的有序执行。然而,由于涉及线程的阻塞与唤醒,使用时需谨慎,避免死锁和资源浪费。

    C多线程编程实战

    - 静态成员、锁和线程局部存储(`ThreadLocal&lt;T&gt;`)是实现线程安全的方法。 - 避免共享状态和使用不可变对象可以减少线程安全问题。 7. **线程优先级** - 操作系统为每个线程分配优先级,但并不保证优先级高的...

Global site tag (gtag.js) - Google Analytics