From 08c5e7e8b8cb69733a7d2bbcdf0414524aab69ec Mon Sep 17 00:00:00 2001 From: Falcon <12919280+falconfly@user.noreply.gitee.com> Date: Wed, 23 Apr 2025 14:51:57 +0800 Subject: [PATCH] =?UTF-8?q?=E6=96=B0=E5=A2=9E=E7=BA=BF=E7=A8=8B=E5=AE=89?= =?UTF-8?q?=E5=85=A8=E5=AE=9A=E9=95=BF=E9=98=9F=E5=88=97?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../ThreadSafeFixedSizeQueueTest.cs | 60 +++++++++ Falcon.SugarApi/ThreadSafeFixedSizeQueue.cs | 123 ++++++++++++++++++ 2 files changed, 183 insertions(+) create mode 100644 Falcon.SugarApi.Test/ThreadSafeFixedSizeQueueTest.cs create mode 100644 Falcon.SugarApi/ThreadSafeFixedSizeQueue.cs diff --git a/Falcon.SugarApi.Test/ThreadSafeFixedSizeQueueTest.cs b/Falcon.SugarApi.Test/ThreadSafeFixedSizeQueueTest.cs new file mode 100644 index 0000000..6304184 --- /dev/null +++ b/Falcon.SugarApi.Test/ThreadSafeFixedSizeQueueTest.cs @@ -0,0 +1,60 @@ +using Microsoft.VisualStudio.TestTools.UnitTesting; + +namespace Falcon.SugarApi.Test +{ + /// + /// 任务防抖测试 + /// + [TestClass()] + public class ThreadSafeFixedSizeQueueTest + { + /// + /// 出入数据测试 + /// + [TestMethod()] + public void TestInOut() { + var queue = new ThreadSafeFixedSizeQueue(3); + + var i = queue.Dequeue(); + Assert.IsTrue(i == 0); + + queue.Enqueue(1); + Assert.IsTrue(queue.Count == 1); + + i = queue.Dequeue(); + Assert.IsTrue(i == 1); + + + queue.Enqueue(1); + queue.Enqueue(2); + queue.Enqueue(3); + queue.Enqueue(4); + queue.Enqueue(5); + Assert.IsTrue(queue.Count == 3); + i = queue.Dequeue(); + Assert.IsTrue(i == 3); + i = queue.Dequeue(); + Assert.IsTrue(i == 4); + i = queue.Dequeue(); + Assert.IsTrue(i == 5); + Assert.IsTrue(queue.Count == 0); + + queue.Enqueue(1); + queue.Enqueue(2); + queue.Enqueue(3); + queue.Clear(); + Assert.IsTrue(queue.Count == 0); + i = queue.Dequeue(); + Assert.IsTrue(i == 0); + + queue.Enqueue(1); + queue.Enqueue(2); + queue.Enqueue(3); + int id = 1; + while(queue.TryDequeue(out i)) { + Assert.IsTrue(i == id++); + } + Assert.IsTrue(queue.Count == 0); + } + } +} diff --git a/Falcon.SugarApi/ThreadSafeFixedSizeQueue.cs b/Falcon.SugarApi/ThreadSafeFixedSizeQueue.cs new file mode 100644 index 0000000..0f8ab0b --- /dev/null +++ b/Falcon.SugarApi/ThreadSafeFixedSizeQueue.cs @@ -0,0 +1,123 @@ +using System; + +namespace Falcon.SugarApi +{ + /// + /// 线程安全的固定长度先入先出队列 + /// + /// + public class ThreadSafeFixedSizeQueue + { + private readonly T[] _buffer; + /// + /// 最新添加的元素 + /// + private int _head; + /// + /// 最早加入的元素 + /// + private int _tail; + /// + /// 当前元素数量 + /// + public int Count { get; private set; } + /// + /// 线程安全锁 + /// + private readonly object _lock = new object(); + /// + /// 元素数量 + /// + public int Capacity { get; private set; } + /// + /// 通过指定元素数量实例化固定长度的线程安全队列 + /// + /// 队列长度 + /// 参数异常 + public ThreadSafeFixedSizeQueue(int capacity) { + if(capacity <= 0) + throw new ArgumentException("Capacit只能是正整数",nameof(capacity)); + + Capacity = capacity; + _buffer = new T[capacity]; + _head = 0; + _tail = 0; + this.Count = 0; + } + + /// + /// 添加元素到队列,队列满时自动覆盖最早加入的元素 + /// + public void Enqueue(T item) { + lock(_lock) { + if(this.Count == 0) { + _head = 0; + _tail = 0; + this.Count = 1; + _buffer[0] = item; + return; + } + if(this.Count == this.Capacity) { + headMoveNext(); + tailMoveNext(); + _buffer[_head] = item; + return; + } + headMoveNext(); + this.Count++; + this._buffer[_head] = item; + } + } + + /// + /// 移除并返回队列尾部的元素 + /// + public T? Dequeue() { + if(this.Count == 0) + return default; + lock(_lock) { + T item = _buffer[this._tail]; + tailMoveNext(); + this.Count--; + return item; + } + } + /// + /// 尝试获取队列尾部元素 + /// + /// + /// + public bool TryDequeue(out T? item) { + if(Count == 0) { + item = default; + return false; + } + lock(_lock) { + item = _buffer[_tail]; + Count--; + tailMoveNext(); + return true; + } + } + /// + /// 清除队列内元素 + /// + public void Clear() { + lock(_lock) { + _head = 0; + _tail = 0; + Count = 0; + } + } + + /// + /// 头位置移至下一位 + /// + private int headMoveNext() => _head = (_head + 1) % Capacity; + /// + /// 尾位置头位置移至下一位 + /// + private int tailMoveNext() => _tail = (_tail + 1) % Capacity; + + } +}