C#中三种高效且可靠的线程间通讯方案
1. AutoResetEvent
AutoResetEvent 是一种同步原语,它允许一个线程等待另一个线程发出信号。当一个线程调用 WaitOne() 方法时,它会被阻塞直到另一个线程调用 Set() 方法为止。每次 Set() 被调用后,AutoResetEvent 将自动重置为非信号状态,这意味着只能唤醒一个等待的线程。
using System;
using System.Threading;
class Program
{
static AutoResetEvent autoResetEvent = new AutoResetEvent(false);
static void Main()
{
Thread workerThread = new Thread(WorkerMethod);
workerThread.Start();
Console.WriteLine("主线程:启动工作线程");
Thread.Sleep(1000); // 模拟一些操作
Console.WriteLine("主线程:发出信号让工作线程继续");
autoResetEvent.Set(); // 发出信号
}
static void WorkerMethod()
{
Console.WriteLine("工作线程:正在等待信号...");
autoResetEvent.WaitOne(); // 等待信号
Console.WriteLine("工作线程:收到信号,继续执行");
}
}
1. ManualResetEvent
与 AutoResetEvent 类似,ManualResetEvent 允许一个或多个线程等待某个事件的发生。不同的是,ManualResetEvent 在 Set() 被调用之后不会自动重置,除非显式地调用了 Reset() 方法。
using System;
using System.Threading;
class Program
{
static ManualResetEvent manualResetEvent = new ManualResetEvent(false);
static void Main()
{
for (int i = 0; i < 3; i++)
{
Thread workerThread = new Thread(WorkerMethod);
workerThread.Start(i + 1);
}
Console.WriteLine("主线程:所有工作线程已启动,等待它们准备就绪...");
Thread.Sleep(1000); // 模拟一些操作
Console.WriteLine("主线程:发出信号让所有工作线程继续");
manualResetEvent.Set(); // 发出信号
// 手动重置ManualResetEvent
manualResetEvent.Reset();
}
static void WorkerMethod(object threadId)
{
Console.WriteLine($"工作线程 {threadId}:正在等待信号...");
manualResetEvent.WaitOne(); // 等待信号
Console.WriteLine($"工作线程 {threadId}:收到信号,继续执行");
}
}
3. 事件(Event)机制
通过事件和委托机制,可以在对象之间发送消息并通知订阅者。这种模式非常适合需要跨多个线程进行通信的情况,尤其是在图形用户界面(GUI)应用中,主线程通常用于UI更新,而子线程则处理后台任务。
using System;
using System.Threading;
public class Publisher
{
public event EventHandler<int> ProgressChanged;
protected virtual void OnProgressChanged(int progress)
{
ProgressChanged?.Invoke(this, progress);
}
public void DoWork()
{
for (int i = 0; i <= 100; i += 20)
{
Thread.Sleep(500); // 模拟工作进度
OnProgressChanged(i);
}
}
}
public class Subscriber
{
private readonly Publisher _publisher;
public Subscriber(Publisher publisher)
{
_publisher = publisher;
_publisher.ProgressChanged += HandleProgressChanged;
}
private void HandleProgressChanged(object sender, int progress)
{
Console.WriteLine($"Subscriber: 工作进度更新到 {progress}%");
}
}
class Program
{
static void Main()
{
var publisher = new Publisher();
var subscriber = new Subscriber(publisher);
Thread workThread = new Thread(publisher.DoWork);
workThread.Start();
}
}
总结
上述三种方法都展示了如何在线程之间安全地传递信息,避免了直接共享资源可能导致的竞争条件。每种方法都有其适用场景,开发者可以根据具体的需求选择最适合的技术2。例如,在需要精确控制哪些线程被释放的情况下,AutoResetEvent 和 ManualResetEvent 都是非常合适的选择;而在复杂的多线程环境中,使用事件和委托机制可以更方便地管理组件之间的交互。