C#中三种高效且可靠的线程间通讯方案

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 都是非常合适的选择;而在复杂的多线程环境中,使用事件和委托机制可以更方便地管理组件之间的交互。

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值