1.1 详细使用AutoResetEvent

AutoResetEvent 是一个用于线程间同步的机制,它通过发出信号让某个线程继续执行,并在一个线程被释放后自动将状态重置为无信号状态,确保后续的线程必须等待新的信号。

下面我将详细介绍如何使用 AutoResetEvent,并通过代码示例帮助理解其具体工作方式。

AutoResetEvent 的构造方法

AutoResetEvent 有一个构造方法:

public AutoResetEvent(bool initialState)
  • initialState 参数是一个布尔值,如果为 true,表示初始状态为有信号,线程可以直接通过;如果为 false,表示初始状态为无信号,线程需要等待。

常用方法

  • WaitOne():用于阻塞当前线程,直到 AutoResetEvent 变成有信号状态。
  • Set():将 AutoResetEvent 设置为有信号状态,释放一个等待的线程,并自动将状态重置为无信号状态。
  • Reset():手动将 AutoResetEvent 设置为无信号状态,但在 AutoResetEvent 中,这个方法很少使用,因为其会自动重置。

工作流程

  1. 线程调用 WaitOne() 来等待信号。
  2. 如果信号是无信号状态,线程会被阻塞。
  3. 另一个线程调用 Set()AutoResetEvent 变为有信号状态,释放一个线程。
  4. AutoResetEvent 自动重置为无信号状态,其它等待的线程仍需等待。

代码示例

下面是一个简单的例子,展示了如何使用 AutoResetEvent 来同步两个线程的执行。

using System;
using System.Threading;

class Program
{
    static AutoResetEvent autoResetEvent = new AutoResetEvent(false);

    static void Main(string[] args)
    {
        // 创建两个线程
        Thread t1 = new Thread(Thread1Work);
        Thread t2 = new Thread(Thread2Work);

        // 启动线程
        t1.Start();
        t2.Start();

        // 主线程等待两秒后发出信号,允许 t1 线程继续执行
        Thread.Sleep(2000);
        Console.WriteLine("主线程:允许线程1执行");
        autoResetEvent.Set();

        // 主线程等待两秒后发出信号,允许 t2 线程继续执行
        Thread.Sleep(2000);
        Console.WriteLine("主线程:允许线程2执行");
        autoResetEvent.Set();

        // 等待两个线程完成
        t1.Join();
        t2.Join();

        Console.WriteLine("主线程:所有工作线程都已完成");
    }

    // 线程1的工作
    static void Thread1Work()
    {
        Console.WriteLine("线程1:等待信号...");
        autoResetEvent.WaitOne(); // 等待信号
        Console.WriteLine("线程1:接收到信号,继续执行...");
    }

    // 线程2的工作
    static void Thread2Work()
    {
        Console.WriteLine("线程2:等待信号...");
        autoResetEvent.WaitOne(); // 等待信号
        Console.WriteLine("线程2:接收到信号,继续执行...");
    }
}

代码详解

  1. 创建 AutoResetEvent​ ** 对象**:在主线程中创建一个 AutoResetEvent 实例,并将初始状态设置为 false(无信号),这意味着一开始所有线程都必须等待信号。

    static AutoResetEvent autoResetEvent = new AutoResetEvent(false);
    
  2. 线程1 和线程2

    • 每个线程都调用 WaitOne() 方法等待信号。这时由于 AutoResetEvent 是无信号状态,两个线程都会阻塞,等待主线程发出信号。
    • Thread.Sleep(2000) 用于模拟主线程的一些延迟操作,表示在某些情况下,主线程可能会有工作需要完成。
  3. 发出信号

    • 主线程调用 Set() 方法发出信号,让 AutoResetEvent 进入有信号状态,释放一个等待的线程(在这里,首先是 Thread1)。
    • AutoResetEvent 在释放了线程1之后,自动重置为无信号状态,这意味着线程2仍然需要等待下一个 Set() 信号。
  4. 同步执行顺序

    • 主线程等待两秒后再调用 Set(),此时释放线程2,确保两个线程有序执行。

执行结果

线程1:等待信号...
线程2:等待信号...
主线程:允许线程1执行
线程1:接收到信号,继续执行...
主线程:允许线程2执行
线程2:接收到信号,继续执行...
主线程:所有工作线程都已完成

在上面的输出中,可以看到 AutoResetEvent 确保了线程1和线程2依次按顺序执行,而不是同时执行。

实际应用场景

AutoResetEvent 非常适合以下场景:

  1. 线程之间的同步:当需要确保某个线程的执行必须在另一个线程完成某项任务后再进行时,使用 AutoResetEvent 能够很好地协调执行顺序。
  2. 资源共享:如果多个线程需要访问共享资源,但每次只能允许一个线程访问,AutoResetEvent 可以控制对资源的顺序访问。

小结

  • AutoResetEvent 是一种自动重置的线程同步机制,能够协调多个线程的执行顺序。
  • 通过 Set()WaitOne() 方法,线程可以等待信号或者释放信号。
  • 适合需要依次让多个线程执行的场景。

在实际开发中,AutoResetEvent 经常用于控制线程间的顺序,避免资源竞争问题,确保程序的正确性。