在多线程编程中,数据结构的线程安全性至关重要。C# 提供了多种线程安全集合,但标准库中并没有直接提供线程安全的 双端队列(Deque)。本文将手把手教你如何使用 C# 实现一个高性能、线程安全的双端队列,适合初学者和中级开发者。
双端队列(Double-ended Queue,简称 Deque)是一种允许在两端高效插入和删除元素的数据结构。它结合了栈(Stack)和队列(Queue)的特性:
在 C# 中,虽然 .NET 提供了 Queue<T> 和 Stack<T>,但没有内置的 Deque<T>,更不用说线程安全版本了。
当多个线程同时访问同一个双端队列时,如果没有适当的同步机制,可能会导致数据损坏、异常或不可预测的行为。因此,在并发环境中,必须确保操作的原子性和一致性。这就是 C#线程安全双端队列 的价值所在。
我们将基于 List<T> 构建一个简单的双端队列,并使用 lock 关键字来保证线程安全。虽然性能不如无锁结构,但对于大多数应用场景已足够,且代码清晰易懂。
核心方法包括:
AddToFront(T item):在队列前端添加元素AddToBack(T item):在队列尾端添加元素RemoveFromFront():从队列前端移除并返回元素RemoveFromBack():从队列尾端移除并返回元素Count:获取当前元素数量using System;using System.Collections.Generic;/// <summary>/// 线程安全的双端队列实现/// </summary>/// <typeparam name="T">队列中元素的类型</typeparam>public class ConcurrentDeque<T>{ private readonly List<T> _items = new List<T>(); private readonly object _lock = new object(); /// <summary> /// 在队列前端添加元素 /// </summary> public void AddToFront(T item) { lock (_lock) { _items.Insert(0, item); } } /// <summary> /// 在队列尾端添加元素 /// </summary> public void AddToBack(T item) { lock (_lock) { _items.Add(item); } } /// <summary> /// 从队列前端移除并返回元素 /// </summary> /// <returns>被移除的元素</returns> /// <exception cref="InvalidOperationException">当队列为空时抛出</exception> public T RemoveFromFront() { lock (_lock) { if (_items.Count == 0) throw new InvalidOperationException("双端队列为空"); T item = _items[0]; _items.RemoveAt(0); return item; } } /// <summary> /// 从队列尾端移除并返回元素 /// </summary> /// <returns>被移除的元素</returns> /// <exception cref="InvalidOperationException">当队列为空时抛出</exception> public T RemoveFromBack() { lock (_lock) { if (_items.Count == 0) throw new InvalidOperationException("双端队列为空"); T item = _items[_items.Count - 1]; _items.RemoveAt(_items.Count - 1); return item; } } /// <summary> /// 获取队列中元素的数量 /// </summary> public int Count { get { lock (_lock) { return _items.Count; } } } /// <summary> /// 检查队列是否为空 /// </summary> public bool IsEmpty { get { lock (_lock) { return _items.Count == 0; } } }} 下面是一个简单的多线程使用示例,展示如何安全地在多个线程中操作我们的 ConcurrentDeque<int>:
using System;using System.Threading.Tasks;class Program{ static async Task Main(string[] args) { var deque = new ConcurrentDeque<int>(); // 启动两个任务:一个从前端添加,一个从后端添加 var task1 = Task.Run(() => { for (int i = 0; i < 1000; i++) { deque.AddToFront(i); } }); var task2 = Task.Run(() => { for (int i = 1000; i < 2000; i++) { deque.AddToBack(i); } }); await Task.WhenAll(task1, task2); Console.WriteLine($"最终队列长度: {deque.Count}"); // 应输出 2000 // 安全地清空队列 while (!deque.IsEmpty) { try { deque.RemoveFromFront(); } catch (InvalidOperationException) { // 多线程环境下可能有竞争,但我们的实现已处理 break; } } Console.WriteLine($"清空后队列长度: {deque.Count}"); // 应输出 0 }} 上述实现使用 lock 确保了 C#并发集合 的线程安全,但频繁的 Insert(0, item) 操作会导致 List<T> 内部数组大量移动,时间复杂度为 O(n)。对于高性能场景,可考虑以下优化:
ReaderWriterLockSlim)提升读多写少场景的性能ConcurrentQueue<T> 源码,学习无锁(lock-free)设计思想通过本教程,你已经学会了如何在 C# 中实现一个基础但功能完整的 线程安全双端队列。虽然这不是生产环境中的最优解,但它清晰展示了同步机制的应用,并为你深入理解 C#双端队列 和并发编程打下坚实基础。
记住,实际项目中应优先考虑使用 .NET 提供的成熟并发集合(如 ConcurrentQueue、ConcurrentStack),只有在确实需要双端操作时,才考虑自定义实现。
关键词回顾:C#双端队列、线程安全双端队列、C#并发集合、双端队列实现。
本文由主机测评网于2025-12-06发表在主机测评网_免费VPS_免费云服务器_免费独立服务器,如有疑问,请联系我们。
本文链接:https://www.vpshk.cn/2025123996.html