C# | 使用AutoResetEvent和ManualResetEvent进行线程同步和通信

使用AutoResetEvent和ManualResetEvent进行线程同步和通信

文章目录

介绍

在多线程编程中,AutoResetEvent 和 ManualResetEvent 是两个常用的同步原语。它们用于线程间的通信和协调,以确保线程按照特定的顺序执行。本篇博客将介绍这两种同步原语的概念、用法和区别。

AutoResetEvent

AutoResetEvent (自动重置事件)是一个同步基元,它允许一个线程等待其他线程在信号状态之前进行等待,用于在线程间提供简单的信号通知机制。它的工作方式是,当一个线程通过调用 WaitOne() 方法等待事件信号时,如果事件处于非终止状态,线程将被阻塞。当另一个线程调用 Set() 方法将事件设置为终止状态时,等待的线程将被唤醒,并且事件将自动重置为非终止状态。

ManualResetEvent

ManualResetEvent (手动重置事件)也是一个同步基元,它与AutoResetEvent类似,也用于在线程间提供信号通知机制。与 AutoResetEvent 不同的是,ManualResetEvent 在设置为终止状态后,会一直保持终止状态,直到调用 Reset() 方法将其重置为非终止状态。另外,它允许所有等待的线程 在同一个信号状态下被唤醒。当一个线程通过调用 WaitOne() 方法等待事件信号时,如果事件处于非终止状态,线程将被阻塞。只有当事件被设置为终止状态时,线程才会被唤醒。

异同点

虽然 AutoResetEvent 和 ManualResetEvent 都用于线程间的同步和通信,它们之间有以下几个关键的异同点:

  • 重置行为 :AutoResetEvent 在一个等待线程被唤醒后会自动将事件重置为非终止状态,而 ManualResetEvent 则需要显式地调用 Reset() 方法将事件重置为非终止状态。
  • 信号通知:AutoResetEvent 只允许一个等待线程被唤醒,即使有多个线程等待;而 ManualResetEvent 允许多个等待线程被唤醒。
  • 等待过程:AutoResetEvent 在一个等待线程被唤醒后,其他等待线程仍然会继续等待;而 ManualResetEvent 在一个等待线程被唤醒后,所有等待线程都会被唤醒。

使用场景和代码示例

根据上述的异同点,我们可以根据不同的需求来选择使用 AutoResetEvent 或 ManualResetEvent。

AutoResetEvent 使用示例

我们创建了两个工作线程,并使用 AutoResetEvent 来同步它们的执行。在主线程中,我们先唤醒第一个等待线程,然后等待一段时间再唤醒第二个等待线程。这样,每个线程只会被唤醒一次,然后自动重置事件,继续等待下一个信号。

csharp 复制代码
  using System;
  using System.Threading;

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

      static void Main(string[] args)
      {
          Thread thread1 = new Thread(Worker);
          Thread thread2 = new Thread(Worker);

          thread1.Start();
          thread2.Start();

          // 唤醒第一个等待线程
          autoResetEvent.Set();

          // 唤醒第二个等待线程
          Thread.Sleep(1000);
          autoResetEvent.Set();

          // 等待线程执行完毕
          thread1.Join();
          thread2.Join();
      }

      static void Worker()
      {
          Console.WriteLine("Worker started");
          autoResetEvent.WaitOne();
          Console.WriteLine("Worker finished");
      }
  }

ManualResetEvent 使用示例

我们同样创建了两个工作线程,但这次使用ManualResetEvent 来同步它们的执行。在主线程中,我们设置了事件为终止状态,这将唤醒所有等待线程。由于 ManualResetEvent 保持终止状态,每个线程只会被唤醒一次,然后继续执行直到结束。

csharp 复制代码
  using System;
  using System.Threading;

  class Program
  {
      static ManualResetEvent manualResetEvent = newManualResetEvent(true);

      static void Main(string[] args)
      {
          Thread thread1 = new Thread(Worker);
          Thread thread2 = new Thread(Worker);

          thread1.Start();
          thread2.Start();

          // 唤醒所有等待线程
          manualResetEvent.Set();

          // 等待线程执行完毕
          thread1.Join();
          thread2.Join();
      }

      static void Worker()
      {
          Console.WriteLine("Worker started");
          manualResetEvent.WaitOne();
          Console.WriteLine("Worker finished");
      }
  }

阻塞多个线程并同时激活

如果需要阻塞多个线程并同时激活多个线程,建议使用 ManualResetEvent。原因是 ManualResetEvent 允许多个等待线程被唤醒,而 AutoResetEvent 只允许一个等待线程被唤醒。

下面是一个使用 ManualResetEvent 的示例代码:

csharp 复制代码
using System;
using System.Threading;

class Program
{
    static ManualResetEvent manualResetEvent = new ManualResetEvent(false);

    static void Main(string[] args)
    {
        Thread[] threads = new Thread[5];

        for (int i = 0; i < threads.Length; i++)
        {
            threads[i] = new Thread(Worker);
            threads[i].Start();
        }

        // 阻塞所有线程
        Console.WriteLine("Blocking all threads...");
        manualResetEvent.WaitOne();

        // 激活所有线程
        Console.WriteLine("Activating all threads...");
        manualResetEvent.Set();

        // 等待线程执行完毕
        foreach (Thread thread in threads)
        {
            thread.Join();
        }
    }

    static void Worker()
    {
        Console.WriteLine("Worker started");
        manualResetEvent.WaitOne();
        Console.WriteLine("Worker finished");
    }
}

在示例中创建了 5 个工作线程,并使用 ManualResetEvent 来阻塞和激活这些线程。执行的流程为:

  1. 主线程将 ManualResetEvent 设置为非终止状态,阻塞所有的工作线程;
  2. 主线程打印消息并将 ManualResetEvent 设置为终止状态,激活所有的工作线程;
  3. 等待所有线程执行完毕。
相关推荐
i橡皮擦9 小时前
TheIsle恐龙岛读取游戏基址做插件(C#语言)
开发语言·游戏·c#·恐龙岛·theisle
simon_skywalker11 小时前
软件工程(三) 软件开发环境、工具、重用、再工程、产品线
软件工程
雾江流13 小时前
小喵播放器 1.1.5| 视频超分提升画质,支持网页视频,B站番剧
音视频·软件工程
Filotimo_15 小时前
流媒体的概念
信息与通信
用户219916797039115 小时前
C# 14 中的新增功能
c#
Coder_Boy_15 小时前
基于SpringAI的在线考试系统-企业级软件研发工程应用规范案例
java·运维·spring boot·软件工程·devops
北京耐用通信15 小时前
耐达讯自动化CANopen转Profibus网关在矿山机械RFID读写器应用中的技术分析
人工智能·科技·物联网·自动化·信息与通信
垂葛酒肝汤16 小时前
放置挂机游戏的离线和在线收益unity实现
游戏·unity·c#
卡奥斯开源社区官方16 小时前
Claude 4.5技术深析:AI编码重构软件工程的底层逻辑与实践路径
人工智能·重构·软件工程