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;
+
+ }
+}