菜单
本页目录

区别与示例

AutoResetEvent 和 ManualResetEvent 十分相似。两者之间的区别,在于前者是自动(Auto),后者是手动(Manua)。

你可以先运行下面的示例,再测试两者的区别。

AutoResetEvent 示例:

class Program
{
    // 线程通知
    private static AutoResetEvent resetEvent = new AutoResetEvent(false);

    static void Main(string[] args)
    {
        // 创建线程
        new Thread(DoOne).Start();

        // 用于不断向另一个线程发送信号
        while (true)
        {
            Console.ReadKey();
            resetEvent.Set();           // 发生通知,设置终止状态
        }
    }

    public static void DoOne()
    {
        Console.WriteLine("① 等待中,请发出信号允许我运行");
        resetEvent.WaitOne();

        Console.WriteLine("② 等待中,请发出信号允许我运行");

        resetEvent.WaitOne();
        Console.WriteLine("③ 等待中,请发出信号允许我运行");

        // ...

        Console.WriteLine("线程结束");
    }
}

ManualResetEvent 类示例:

class Program
{
    private static ManualResetEvent resetEvent = new ManualResetEvent(false);
    static void Main(string[] args)
    {
        new Thread(DoOne).Start();
        // 用于不断向另一个线程发送信号
        while (true)
        {
            Console.ReadKey();
            resetEvent.Set();           // 发生通知,设置终止状态
        }
    }

    public static void DoOne()
    {
        Console.WriteLine("等待中,请发出信号允许我运行");
        resetEvent.WaitOne();

        // 后面的都无效,线程会直接跳过而无需等待
        resetEvent.WaitOne();
        resetEvent.WaitOne();
        resetEvent.WaitOne();
        resetEvent.WaitOne();
        resetEvent.WaitOne();
        Console.WriteLine("线程结束");
    }
}

因为 AutoResetEvent 对象在 .WaitOne() 方法等待信号完毕后,会自动重置为非终止状态,相当于高速收费站自动闸门,一辆车过去后,机器自动关闸。

ManualResetEvent 相当于人工闸门,打开后编写人工关闭闸门,不然的话闸门会一直处于打开状态。

ManualResetEvent 主要用于更加灵活的线程信号传递场景。

ManualResetEvent 类

表示线程同步事件,收到信号时,要想下一次依然生效,必须手动重置该事件。

因为 ManualResetEvent 类跟 AutoManualResetEvent 类十分接近,这里就不赘述了。

它们的使用区别主要是:

AutoResetEvent 类,每次 Set() ,跳过一个 WaitOne()。因为会 自动恢复设置,所以下次碰到 WaitOne() 会继续等待。

ManualResetEvent 类, Set() 后,不会重置设置,因此一旦使用了 Set() 后,就会一路放通,不会再等待。

其构造函数如下:

构造函数说明
ManualResetEvent(Boolean)用一个指示是否将初始状态设置为终止的布尔值初始化 ManualResetEvent 类的新实例。

其常用方法如下:

方法说明
Close()释放由当前 WaitHandle 占用的所有资源。
Reset()将事件状态设置为非终止,从而导致线程受阻。
Set()将事件状态设置为有信号,从而允许一个或多个等待线程继续执行。
WaitOne()阻止当前线程,直到当前 WaitHandle 收到信号。
WaitOne(Int32)阻止当前线程,直到当前 WaitHandle 收到信号,同时使用 32 位带符号整数指定时间间隔(以毫秒为单位)。
WaitOne(Int32, Boolean)阻止当前线程,直到当前的 WaitHandle 收到信号为止,同时使用 32 位带符号整数指定时间间隔,并指定是否在等待之前退出同步域。
WaitOne(TimeSpan)阻止当前线程,直到当前实例收到信号,同时使用 TimeSpan 指定时间间隔。
WaitOne(TimeSpan, Boolean)阻止当前线程,直到当前实例收到信号为止,同时使用 TimeSpan 指定时间间隔,并指定是否在等待之前退出同步域。

ManualResetEventSlim

ManualResetEventSlim 相对 ManualResetEvent ,当等待时间预计非常短并且事件不跨越进程边界时,可以使用此类来获得比 ManualResetEvent 更好的性能。

从代码使用来看,没有啥区别,主要就是考虑性能下时,两者不同场景。

这里就不对这两个类型赘述了。