2021-03-29 10:23:34 -07:00
|
|
|
|
using System;
|
2023-11-22 15:56:43 -05:00
|
|
|
|
#if NET20 || NET35
|
|
|
|
|
|
using System.Collections.Generic;
|
|
|
|
|
|
#else
|
2021-03-29 10:23:34 -07:00
|
|
|
|
using System.Collections.Concurrent;
|
2023-11-22 15:56:43 -05:00
|
|
|
|
#endif
|
2021-03-31 21:26:55 -07:00
|
|
|
|
using System.Threading;
|
2021-03-29 10:23:34 -07:00
|
|
|
|
using System.Threading.Tasks;
|
|
|
|
|
|
|
2021-09-29 11:48:37 -07:00
|
|
|
|
namespace MPF.Core.Data
|
2021-03-29 10:23:34 -07:00
|
|
|
|
{
|
2023-11-06 23:06:11 -05:00
|
|
|
|
public sealed class ProcessingQueue<T> : IDisposable
|
2021-03-29 10:23:34 -07:00
|
|
|
|
{
|
|
|
|
|
|
/// <summary>
|
|
|
|
|
|
/// Internal queue to hold data to process
|
|
|
|
|
|
/// </summary>
|
2023-11-22 15:56:43 -05:00
|
|
|
|
#if NET20 || NET35
|
|
|
|
|
|
private readonly Queue<T> InternalQueue;
|
|
|
|
|
|
#else
|
2021-03-29 10:23:34 -07:00
|
|
|
|
private readonly ConcurrentQueue<T> InternalQueue;
|
2023-11-22 15:56:43 -05:00
|
|
|
|
#endif
|
2021-03-29 10:23:34 -07:00
|
|
|
|
|
|
|
|
|
|
/// <summary>
|
|
|
|
|
|
/// Custom processing step for dequeued data
|
|
|
|
|
|
/// </summary>
|
|
|
|
|
|
private readonly Action<T> CustomProcessing;
|
|
|
|
|
|
|
2021-03-31 21:26:55 -07:00
|
|
|
|
/// <summary>
|
|
|
|
|
|
/// Cancellation method for the processing task
|
|
|
|
|
|
/// </summary>
|
|
|
|
|
|
private readonly CancellationTokenSource TokenSource;
|
|
|
|
|
|
|
2021-03-29 10:23:34 -07:00
|
|
|
|
public ProcessingQueue(Action<T> customProcessing)
|
|
|
|
|
|
{
|
2023-11-22 15:56:43 -05:00
|
|
|
|
#if NET20 || NET35
|
|
|
|
|
|
this.InternalQueue = new Queue<T>();
|
|
|
|
|
|
#else
|
2021-03-29 10:23:34 -07:00
|
|
|
|
this.InternalQueue = new ConcurrentQueue<T>();
|
2023-11-22 15:56:43 -05:00
|
|
|
|
#endif
|
2021-03-29 10:23:34 -07:00
|
|
|
|
this.CustomProcessing = customProcessing;
|
2021-03-31 21:26:55 -07:00
|
|
|
|
this.TokenSource = new CancellationTokenSource();
|
2023-11-22 15:56:43 -05:00
|
|
|
|
#if NET20 || NET35
|
|
|
|
|
|
Task.Run(() => ProcessQueue());
|
|
|
|
|
|
#elif NET40
|
2023-11-20 16:46:54 -05:00
|
|
|
|
Task.Factory.StartNew(() => ProcessQueue());
|
2023-11-20 13:15:06 -05:00
|
|
|
|
#else
|
2021-04-01 15:10:43 -07:00
|
|
|
|
Task.Run(() => ProcessQueue(), this.TokenSource.Token);
|
2023-11-20 13:15:06 -05:00
|
|
|
|
#endif
|
2021-03-29 10:50:43 -07:00
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
/// <summary>
|
|
|
|
|
|
/// Dispose the current instance
|
|
|
|
|
|
/// </summary>
|
2021-11-26 14:06:57 -08:00
|
|
|
|
public void Dispose() => this.TokenSource.Cancel();
|
2021-03-29 10:50:43 -07:00
|
|
|
|
|
|
|
|
|
|
/// <summary>
|
|
|
|
|
|
/// Enqueue a new item for processing
|
|
|
|
|
|
/// </summary>
|
|
|
|
|
|
/// <param name="item"></param>
|
2023-11-20 13:15:06 -05:00
|
|
|
|
public void Enqueue(T? item)
|
2021-03-29 10:50:43 -07:00
|
|
|
|
{
|
2021-04-01 19:08:39 -07:00
|
|
|
|
// Only accept new data when not cancelled
|
2023-10-07 01:02:21 -04:00
|
|
|
|
if (item != null && !this.TokenSource.IsCancellationRequested)
|
2021-04-01 15:10:43 -07:00
|
|
|
|
this.InternalQueue.Enqueue(item);
|
2021-03-29 10:23:34 -07:00
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
/// <summary>
|
|
|
|
|
|
/// Process
|
|
|
|
|
|
/// </summary>
|
|
|
|
|
|
private void ProcessQueue()
|
|
|
|
|
|
{
|
|
|
|
|
|
while (true)
|
|
|
|
|
|
{
|
|
|
|
|
|
// Nothing in the queue means we get to idle
|
2023-11-22 15:56:43 -05:00
|
|
|
|
#if NET20 || NET35
|
|
|
|
|
|
if (InternalQueue.Count == 0)
|
|
|
|
|
|
#else
|
2023-11-06 23:06:11 -05:00
|
|
|
|
if (InternalQueue.IsEmpty)
|
2023-11-22 15:56:43 -05:00
|
|
|
|
#endif
|
2021-04-01 19:08:39 -07:00
|
|
|
|
{
|
|
|
|
|
|
if (this.TokenSource.IsCancellationRequested)
|
|
|
|
|
|
break;
|
2021-06-14 22:37:47 -07:00
|
|
|
|
|
|
|
|
|
|
Thread.Sleep(10);
|
2021-03-29 10:23:34 -07:00
|
|
|
|
continue;
|
2021-04-01 19:08:39 -07:00
|
|
|
|
}
|
2021-03-29 10:23:34 -07:00
|
|
|
|
|
2023-11-22 15:56:43 -05:00
|
|
|
|
#if NET20 || NET35
|
|
|
|
|
|
// Get the next item from the queue and invoke the lambda, if possible
|
|
|
|
|
|
this.CustomProcessing?.Invoke(this.InternalQueue.Dequeue());
|
|
|
|
|
|
#else
|
2021-03-29 10:23:34 -07:00
|
|
|
|
// Get the next item from the queue
|
2023-10-07 01:02:21 -04:00
|
|
|
|
if (!this.InternalQueue.TryDequeue(out var nextItem))
|
2021-03-29 10:23:34 -07:00
|
|
|
|
continue;
|
|
|
|
|
|
|
|
|
|
|
|
// Invoke the lambda, if possible
|
|
|
|
|
|
this.CustomProcessing?.Invoke(nextItem);
|
2023-11-22 15:56:43 -05:00
|
|
|
|
#endif
|
2021-03-29 10:23:34 -07:00
|
|
|
|
}
|
|
|
|
|
|
}
|
|
|
|
|
|
}
|
|
|
|
|
|
}
|