在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<string> _messages = new BlockingCollection<string>(); 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<string> 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}"); } }
原文地址:https://mp.weixin.qq.com/s?__biz=MzU5NzcwNzcwNQ==&mid=2247494656&idx=2&sn=beca4402f77182f304206df4b4735dff