C# WaitHandle类的几个有用的函数

WaitHandle类还提供静态方法来处理更复杂的同步难题。WaitAny、WaitAll和SignalAndWait方法可对多个句柄执行信号通知和等待操作,这些等待句柄可以是不同类型(包括Mutex和Semaphore,因为它们同样继承自抽象的WaitHandle类)。ManualResetEventSlim和CountdownEvent也能通过它们的WaitHandle属性参与这些方法。

1.WaitAny

WaitHandle.WaitAny 是 .NET 中用于多线程同步的重要方法,它允许线程等待多个同步对象中的任意一个变为信号状态。

函数定义:

cs 复制代码
public static int WaitAny(WaitHandle[] waitHandles);
public static int WaitAny(WaitHandle[] waitHandles, int millisecondsTimeout);
public static int WaitAny(WaitHandle[] waitHandles, TimeSpan timeout);
public static int WaitAny(WaitHandle[] waitHandles, int millisecondsTimeout, bool exitContext);

核心功能

  1. 多等待对象支持:可以同时监视多个等待句柄(如 ManualResetEvent、AutoResetEvent、Mutex、Semaphore 等)

  2. 任意触发机制:只要数组中任何一个等待句柄收到信号,等待就会结束

  3. 超时控制:可以设置超时时间,避免无限期等待

  4. 返回值指示:返回触发等待的句柄在数组中的索引

下面给一个简单的例子:

cs 复制代码
// 创建三个等待句柄
var waitHandle1 = new AutoResetEvent(false);
var waitHandle2 = new ManualResetEvent(false);
var waitHandle3 = new Semaphore(0, 1);

WaitHandle[] handles = { waitHandle1, waitHandle2, waitHandle3 };

// 在另一个线程中设置某个事件
Task.Run(() => {
    Thread.Sleep(1000);
    waitHandle2.Set();  // 触发第二个事件
});

// 等待任意一个事件触发
int signaledIndex = WaitHandle.WaitAny(handles);

Console.WriteLine($"触发的句柄索引: {signaledIndex}");  // 输出: 1 (第二个句柄)

如果你熟悉C# Task 异步编程就知道,Task类也有一个waitAny,他们两很像。

典型应用场景

  1. 多任务完成等待(任一任务完成即可继续)

  2. 多事件响应处理

  3. 超时监控

  4. 资源竞争处理

2.WaitAll

WaitHandle.WaitAll 是 .NET 中用于多线程同步的关键方法,它允许线程等待所有指定的同步对象都变为信号状态。

cs 复制代码
public static bool WaitAll(WaitHandle[] waitHandles);
public static bool WaitAll(WaitHandle[] waitHandles, int millisecondsTimeout);
public static bool WaitAll(WaitHandle[] waitHandles, TimeSpan timeout);
public static bool WaitAll(WaitHandle[] waitHandles, int millisecondsTimeout, bool exitContext);

核心功能

  1. 全等待机制:只有当所有等待句柄都收到信号时才会继续执行

  2. 混合类型支持:可以同时等待不同类型的同步对象(EventWaitHandle、Mutex、Semaphore等)

  3. 超时控制:可以设置等待的超时时间

  4. 原子性操作:确保所有句柄状态被同时检查

同样给一个例子:

cs 复制代码
// 创建三个等待句柄
var handle1 = new ManualResetEvent(false);
var handle2 = new AutoResetEvent(false);
var handle3 = new Semaphore(0, 1);

WaitHandle[] handles = { handle1, handle2, handle3 };

// 在多个线程中设置事件
Task.Run(() => {
    Thread.Sleep(500);
    handle1.Set();
});

Task.Run(() => {
    Thread.Sleep(1000);
    handle2.Set();
});

Task.Run(() => {
    Thread.Sleep(1500);
    handle3.Release();
});

// 等待所有句柄触发
bool allSignaled = WaitHandle.WaitAll(handles, 2000); // 2秒超时

Console.WriteLine($"所有句柄是否都收到信号: {allSignaled}");

重要特性

  1. 同步点:常用于需要多个条件都满足才能继续执行的场景

  2. 返回值: ◦ 成功时返回 true ◦ 超时返回 false

  3. STA线程限制:不能在单线程单元(STA)中使用(如WPF/Windows Forms的UI线程)

  4. 64句柄限制:在部分.NET版本中最多支持64个句柄

典型应用场景

  1. 多任务同步(等待所有任务完成)

  2. 复杂资源申请(需要同时获取多个资源)

  3. 分布式系统协调

  4. 并行计算屏障

3.SignalAndWait

SignalAndWait 是 WaitHandle 类中一个特殊的同步方法,它原子性地执行两个操作:先对一个等待句柄发出信号,然后立即等待另一个等待句柄。

cs 复制代码
public static bool SignalAndWait(WaitHandle toSignal, WaitHandle toWaitOn);
public static bool SignalAndWait(WaitHandle toSignal, WaitHandle toWaitOn, int millisecondsTimeout, bool exitContext);

核心功能

  1. 两步原子操作: ◦ 首先对 toSignal 调用 Set()(发出信号) ◦ 然后对 toWaitOn 调用 WaitOne()(等待)

  2. 线程优先级提升: ◦ 执行此操作时,当前线程会暂时提升优先级,减少上下文切换

  3. 超时控制: ◦ 可以设置等待的超时时间

3.1线程回合模式

cs 复制代码
// 创建两个事件对象
var wh1 = new AutoResetEvent(false);
var wh2 = new AutoResetEvent(false);

// 线程A
Task.Run(() => {
    Console.WriteLine("线程A执行工作1");
    WaitHandle.SignalAndWait(wh1, wh2);  // 通知wh1并等待wh2
    Console.WriteLine("线程A执行工作2");
});

// 线程B
Task.Run(() => {
    Console.WriteLine("线程B执行工作1");
    WaitHandle.SignalAndWait(wh2, wh1);  // 通知wh2并等待wh1
    Console.WriteLine("线程B执行工作2");
});

/* 输出顺序:
   线程A执行工作1
   线程B执行工作1
   (线程汇合)
   线程A执行工作2
   线程B执行工作2
*/

3.2 生产消费模式

cs 复制代码
var itemReady = new AutoResetEvent(false);
var spaceAvailable = new AutoResetEvent(true);

// 生产者
void Producer() {
    while(true) {
        WaitHandle.SignalAndWait(spaceAvailable, itemReady);
        // 生产物品...
    }
}

// 消费者
void Consumer() {
    while(true) {
        WaitHandle.SignalAndWait(itemReady, spaceAvailable);
        // 消费物品...
    }
}

SignalAndWait 提供了一种高效的线程协调机制,特别适合需要精确控制线程执行顺序的场景,但使用时需要特别注意其限制和潜在的死锁风险。

相关推荐
下一站春风里4 小时前
位运算完整学习笔记:按位与(&)+ 异或(^)
开发语言·c++·算法
吴可可1235 小时前
C#调用摄像头拍照的三种API方案
c#
FinelyYang5 小时前
考试系统简答题 AI 阅卷:覆盖度驱动、异步评分与人机协同落地实践
java·大数据·人工智能
天外飞雨道沧桑5 小时前
我在浏览器里练了一个 792 参数的大模型,它学会了补全 JavaScript
开发语言·javascript·ai·ecmascript·ai编程
hhhjhl6 小时前
Yup 跨端三方库仓颉适配全流程
java·开发语言
运维行者_6 小时前
网络监控工具怎么选?从设备监控到智能运维的能力清单
运维·服务器·开发语言·网络·人工智能·支持向量机·php
用户3126874877206 小时前
Java 对象内存布局:压缩指针、对齐填充与 JOL 实测
java
东华果汁哥6 小时前
【Spring AI 实战】从零开始调用大模型接口,构建 Java AI 应用
java·人工智能·spring
“AI国潮设计-小江”7 小时前
【AIGC实战】Python+SDXL打造“潮汕英歌舞IP”万能立牌插件,批量生成“发财元宝蛋糕”视觉营销方案(附源码)
开发语言·人工智能·python·prompt·aigc
Song_RsHt7 小时前
Redis 与微服务,什么场景下无可替代
java·redis·后端·学习·微服务