揭秘C 揭秘ChatGPT之父
创始人
2025-07-13 16:30:37
0

在C#中,线程之间的通信是实现多线程应用程序的关键环节。线程通信不仅确保数据的安全性和一致性,还是实现多线程协作和同步的重要手段。本文将带你深入了解C#中线程通信的多种方式,并通过实例代码展示其应用。

1. 互斥锁(Mutex)和监视器(Monitor)

互斥锁和监视器是C#中实现线程同步的基本机制。它们可以防止多个线程同时访问共享资源,从而避免数据竞争和不一致。

示例代码:使用Monitor实现线程同步

public class Counter
{
    private int _count = 0;

    public void Increment()
    {
        Monitor.Enter(this);
        try
        {
            _count++;
            Console.WriteLine($"Count: {_count} by thread {Thread.CurrentThread.ManagedThreadId}");
        }
        finally
        {
            Monitor.Exit(this);
        }
    }
}

// 使用示例
var counter = new Counter();

Task.Run(() => counter.Increment());
Task.Run(() => counter.Increment());

2. 信号量(Semaphore)和信号量Slim(SemaphoreSlim)

信号量和信号量Slim用于控制对共享资源的访问数量。它们允许多个线程同时访问资源,但会限制访问的最大数量。

示例代码:使用SemaphoreSlim限制并发访问

public class ResourcePool
{
    private SemaphoreSlim _semaphore = new SemaphoreSlim(3); // 限制最大3个线程同时访问

    public async Task AccessResourceAsync()
    {
        await _semaphore.WaitAsync(); // 等待信号量可用
        try
        {
            // 访问共享资源
            Console.WriteLine($"Accessing resource by thread {Thread.CurrentThread.ManagedThreadId}");
            await Task.Delay(1000); // 模拟耗时操作
        }
        finally
        {
            _semaphore.Release(); // 释放信号量
        }
    }
}

// 使用示例
var pool = new ResourcePool();

var tasks = Enumerable.Range(1, 10).Select(i => pool.AccessResourceAsync()).ToArray();
await Task.WhenAll(tasks);

3. 线程间消息传递

在C#中,可以通过多种方式实现线程间的消息传递,如使用QueueUserWorkItem、ThreadPool、BlockingCollection或Channel等。

示例代码:使用BlockingCollection进行线程间消息传递

public class MessageProducerConsumer
{
    private BlockingCollection _messages = new BlockingCollection();

    public void StartProducer()
    {
        Task.Run(() =>
        {
            for (int i = 0; i < 10; i++)
            {
                _messages.Add($"Message {i}"); // 生产消息
                Thread.Sleep(500); // 模拟耗时操作
            }
            _messages.CompleteAdding(); // 表示不再添加消息
        });
    }

    public void StartConsumer()
    {
        Task.Run(() =>
        {
            foreach (var message in _messages.GetConsumingEnumerable())
            {
                Console.WriteLine($"Consumed: {message} by thread {Thread.CurrentThread.ManagedThreadId}");
            }
        });
    }
}

// 使用示例
var producerConsumer = new MessageProducerConsumer();
producerConsumer.StartProducer();
producerConsumer.StartConsumer();

4. 事件(Event)和委托(Delegate)

事件和委托是C#中实现线程间解耦通信的有效方式。事件允许一个线程通知其他线程发生了某个特定的动作或状态变化。

示例代码:使用事件和委托进行线程通信

public class DataProvider
{
    public event Action DataAvailable; // 定义一个事件

    public void SimulateDataGeneration()
    {
        for (int i = 0; i < 5; i++)
        {
            string data = $"Data {i}";
            DataAvailable?.Invoke(data); // 触发事件
            Thread.Sleep(1000); // 模拟耗时操作
        }
    }
}

public class DataConsumer
{
    public void ConsumeData(string data)
    {
        Console.WriteLine($"Consumed data: {data} by thread {Thread.CurrentThread.ManagedThreadId}");
    }
}

相关内容

热门资讯

如何允许远程连接到MySQL数... [[277004]]【51CTO.com快译】默认情况下,MySQL服务器仅侦听来自localhos...
如何利用交换机和端口设置来管理... 在网络管理中,总是有些人让管理员头疼。下面我们就将介绍一下一个网管员利用交换机以及端口设置等来进行D...
施耐德电气数据中心整体解决方案... 近日,全球能效管理专家施耐德电气正式启动大型体验活动“能效中国行——2012卡车巡展”,作为该活动的...
Windows恶意软件20年“... 在Windows的早期年代,病毒游走于系统之间,偶尔删除文件(但被删除的文件几乎都是可恢复的),并弹...
20个非常棒的扁平设计免费资源 Apple设备的平面图标PSD免费平板UI 平板UI套件24平图标Freen平板UI套件PSD径向平...
德国电信门户网站可实时显示全球... 德国电信周三推出一个门户网站,直观地实时提供其安装在全球各地的传感器网络检测到的网络攻击状况。该网站...
着眼MAC地址,解救无法享受D... 在安装了DHCP服务器的局域网环境中,每一台工作站在上网之前,都要先从DHCP服务器那里享受到地址动...
为啥国人偏爱 Mybatis,... 关于 SQL 和 ORM 的争论,永远都不会终止,我也一直在思考这个问题。昨天又跟群里的小伙伴进行...