您的位置:首页 > 汽车 > 新车 > 兰州全面解封最新消息_新手制作ppt详细步骤_广点通和腾讯朋友圈广告区别_引流平台有哪些

兰州全面解封最新消息_新手制作ppt详细步骤_广点通和腾讯朋友圈广告区别_引流平台有哪些

2025/4/10 15:45:40 来源:https://blog.csdn.net/qq_39847278/article/details/145542525  浏览:    关键词:兰州全面解封最新消息_新手制作ppt详细步骤_广点通和腾讯朋友圈广告区别_引流平台有哪些
兰州全面解封最新消息_新手制作ppt详细步骤_广点通和腾讯朋友圈广告区别_引流平台有哪些

总目录


前言

在C#中,AutoResetEvent 是一个用于线程同步的关键类,它位于 System.Threading 命名空间下。它的核心功能是通过信号机制控制线程的执行顺序,允许一个或多个线程等待某个信号后再继续运行。常用于需要线程间通信的场景。


一、核心概念

  • 作用
    • AutoResetEvent 是一种同步原语,用于在多线程环境中实现线程间的等待和通知
    • 通知等待的线程某个事件已发生(如资源就绪、操作完成)。
  • 信号状态
    • 有信号(Signaled):线程调用 WaitOne() 不会被阻塞。
    • 无信号(Non-signaled):线程调用 WaitOne() 会被阻塞,直到信号触发。
  • 自动重置
    • 当一个等待线程被释放后,AutoResetEvent 会自动将状态重置为非信号状态(即非触发状态)。这意味着每次仅允许一个等待线程继续执行。

本文中所描述的 有信号状态、终止状态、触发状态 意义相同,都是同一种状态的不同名称

二、基本用法

1. 构造函数

var autoEvent = new AutoResetEvent(initialState: false); // 初始无信号/或称 未触发
  • initialState:初始化是否为有信号状态(true 表示有信号/或称 已触发,则线程一开始是无需等待信号的)。

2. 关键方法

  • WaitOne():阻塞当前线程,直到事件变为有信号。可以指定超时时间。
    autoEvent.WaitOne(); // 阻塞直到信号触发
    
    • 如果 AutoResetEvent 已经处于有信号状态,那么线程调用 WaitOne() 不会再起阻塞线程的作用。除非调用Reset() 。
  • Set():将事件设置为有信号状态(释放一个等待线程)。
    autoEvent.Set(); // 发送信号,唤醒一个等待线程
    
    • 当调用 Set() 时,若有线程在等待,会释放一个线程并自动重置为无信号状态。
    • 若调用 Set() 时没有线程等待,事件保持有信号状态,直到后续的 WaitOne() 调用自动消费信号并重置。
  • Reset():将事件设置为无信号状态
    autoEvent.Reset(); 
    
    • 手动 Reset() 的用途:
      • 强制将事件设置为无信号状态,无论当前是否有线程在等待。
      • 确保下一轮的 WaitOne() 必须等待对方的信号,避免因事件残留信号导致逻辑错误。

注意:

  • 有信号和无信号状态指的是AutoResetEvent的状态,而不是线程的状态
  • 如果多次调用 Set() 的时间间隔过短,如果第一次 Set() 还没有结束(信号发送需要处理时间),那么第二次 Set() 可能无效(不起作用)。

三、 示例

示例 1:线程等待主线程信号

using System.Threading;class Program
{static AutoResetEvent autoEvent = new AutoResetEvent(false);static void Main(){Thread worker = new Thread(DoWork);worker.Start();// 主线程触发信号Thread.Sleep(2000);Console.WriteLine("主线程发送信号");autoEvent.Set(); // 唤醒工作线程}static void DoWork(){Console.WriteLine("工作线程等待信号...");autoEvent.WaitOne(); // 阻塞直到信号到来Console.WriteLine("工作线程继续执行");}
}

输出

工作线程等待信号...
主线程发送信号
工作线程继续执行

示例 2:主线程等待工作线程信号

using System;
using System.Threading;class Program
{static AutoResetEvent _autoResetEvent = new AutoResetEvent(false);static void Main(string[] args){// 启动一个新线程Thread t = new Thread(Work);t.Start();Console.WriteLine("主线程等待...");// 主线程等待_autoResetEvent.WaitOne();Console.WriteLine("主线程继续执行");}static void Work(){Console.WriteLine("工作线程正在工作...");// 模拟一些工作Thread.Sleep(1000);Console.WriteLine("工作完成,通知主线程");// 发送信号,允许等待的线程继续_autoResetEvent.Set();}
}

在这个例子中,主线程调用 _autoResetEvent.WaitOne(); 等待,而工作线程在完成任务后调用 _autoResetEvent.Set(); 通知主线程继续执行。

输出

主线程等待...
工作线程正在工作...
工作完成,通知主线程
主线程继续执行

示例3:线程执行控制

class Program
{// 控制第一个线程// 第一个线程开始时,AutoResetEvent 处于终止状态,无需等待信号private static AutoResetEvent oneResetEvent = new AutoResetEvent(true);// 控制第二个线程// 第二个线程开始时,AutoResetEvent 处于非终止状态,需要等待信号private static AutoResetEvent twoResetEvent = new AutoResetEvent(false);static void Main(string[] args){new Thread(DoOne).Start();new Thread(DoTwo).Start();Console.ReadKey();}public static void DoOne(){while (true){Console.WriteLine("\n① 按下任意键,我就让DoTwo运行");Console.ReadKey();twoResetEvent.Set();oneResetEvent.Reset();// 等待 DoTwo() 给我信号oneResetEvent.WaitOne();Console.ForegroundColor = ConsoleColor.Green;Console.WriteLine("\n     DoOne() 执行");Console.ForegroundColor = ConsoleColor.White;}}public static void DoTwo(){while (true){Thread.Sleep(TimeSpan.FromSeconds(1));// 等待 DoOne() 给我信号twoResetEvent.WaitOne();Console.ForegroundColor = ConsoleColor.Yellow;Console.WriteLine("\n     DoTwo() 执行");Console.ForegroundColor = ConsoleColor.White;Console.WriteLine("\n② 按下任意键,我就让DoOne运行");Console.ReadKey();oneResetEvent.Set();twoResetEvent.Reset();}}
}

代码分析

  • DoOne 线程流程

    • 调用 twoResetEvent.Set():通知 DoTwo 可以运行。
    • 手动调用 oneResetEvent.Reset():强制将 oneResetEvent 设为非终止状态。
    • 调用 oneResetEvent.WaitOne():阻塞等待 DoTwo 的 Set()。
  • DoTwo 线程流程

    • 调用 twoResetEvent.WaitOne():等待 DoOne 的信号。
    • 执行完成后,调用 oneResetEvent.Set():通知 DoOne 继续。
    • 手动调用 twoResetEvent.Reset():强制将 twoResetEvent 设为非终止状态。
  • 关键点

    • 手动 Reset() 的目的是立即重置事件状态,确保下一轮循环必须严格等待对方的信号。
    • 若省略 Reset(),事件可能残留终止状态,导致 WaitOne() 直接通过,破坏交替逻辑。
    • 必须保留 Reset():
      • oneResetEvent.Reset() 确保 DoOne 必须等待 DoTwo 的信号。
      • twoResetEvent.Reset() 确保 DoTwo 必须等待 DoOne 的信号。
      • 若省略,残留信号会导致线程间同步失效,破坏交替执行的预期逻辑。
  • 省略 Reset() 场景:省略 oneResetEvent.Reset()

    • 假设 DoOne 未调用 oneResetEvent.Reset():
      • DoOne 调用 twoResetEvent.Set(),通知 DoTwo 运行。
      • DoOne 调用 oneResetEvent.WaitOne()。
        • 若 oneResetEvent 仍为终止状态(例如,DoTwo 在上一轮已调用 Set()),WaitOne() 会直接通过,无需等待。
        • 导致 DoOne 和 DoTwo 同时执行,破坏交替逻辑。

四、高级用法

1. 超时等待

bool signaled = autoEvent.WaitOne(TimeSpan.FromSeconds(5)); // 最多等待5秒
if (!signaled)
{Console.WriteLine("等待超时");
}

2. 多线程竞争

// 多个线程等待同一个事件
for (int i = 0; i < 3; i++)
{new Thread(() => {autoEvent.WaitOne();Console.WriteLine($"线程 {Thread.CurrentThread.ManagedThreadId} 被唤醒");}).Start();
}// 需要调用 Set() 三次才能唤醒所有线程
autoEvent.Set(); // 唤醒第一个线程
autoEvent.Set(); // 唤醒第二个线程
autoEvent.Set(); // 唤醒第三个线程

5、 注意事项

  1. 资源释放:用完需调用 Dispose() 或使用 using 块(AutoResetEvent 继承自 WaitHandle)。
  2. 竞态条件:确保 Set()WaitOne() 的调用顺序合理,避免死锁。
  3. 与 ManualResetEvent 的区别
    • AutoResetEvent 自动重置信号,适合一次唤醒一个线程。
    • ManualResetEvent 需手动调用 Reset(),适合广播多个线程。

六、替代方案

  • ManualResetEventSlim:轻量级版本,性能更优。
  • SemaphoreSlim:控制并发访问数量。
  • TaskCompletionSource:基于任务的异步模式(TAP)。

结语

回到目录页:C#/.NET 知识汇总
希望以上内容可以帮助到大家,如文中有不对之处,还请批评指正。


参考资料:
自动线程通知 AutoResetEvent

版权声明:

本网仅为发布的内容提供存储空间,不对发表、转载的内容提供任何形式的保证。凡本网注明“来源:XXX网络”的作品,均转载自其它媒体,著作权归作者所有,商业转载请联系作者获得授权,非商业转载请注明出处。

我们尊重并感谢每一位作者,均已注明文章来源和作者。如因作品内容、版权或其它问题,请及时与我们联系,联系邮箱:809451989@qq.com,投稿邮箱:809451989@qq.com