A thread-safe looping queue implementation for .NET. CycleKit provides data structures like ConcurrentLoopingQueue<T> that cycle through items infinitely without reallocating. Ideal for scenarios like round-robin dispatching, UI carousels, or audio/video playlist cycling.
$ dotnet add package DCTekSolutions.CycleKitCycleKit provides a powerful, thread-safe queue that cycles endlessly through items.
Perfect for round-robin processing, rotating playlists, or any scenario where looping through a fixed set of items is
needed.
Free to use for personal and commercial projects. This package is closed source.
ConcurrentLoopingQueue<T>)Try pattern for non-throwing accesspublic class ServerNode
{
public string Hostname { get; init; }
public bool IsOnline { get; set; }
public void HandleRequest(string request)
{
Console.WriteLine($"{Hostname} processing: {request}");
}
}
// Setup the pool
var nodes = new List<ServerNode>
{
new() { Hostname = "api-node-1", IsOnline = true },
new() { Hostname = "api-node-2", IsOnline = true },
new() { Hostname = "api-node-3", IsOnline = true }
};
var queue = new ConcurrentLoopingQueue<ServerNode>(nodes);
// Simulate incoming requests
for (int i = 0; i < 10; i++)
{
if (queue.TryNext(out var server) && server.IsOnline)
{
server.HandleRequest($"Request #{i + 1}");
}
}
public class Worker
{
public string Id { get; init; }
public async Task ProcessJobAsync(string job)
{
Console.WriteLine($"[{Id}] started: {job}");
await Task.Delay(250); // simulate work
Console.WriteLine($"[{Id}] finished: {job}");
}
}
var workers = new List<Worker>
{
new() { Id = "Worker-A" },
new() { Id = "Worker-B" },
new() { Id = "Worker-C" }
};
var workerQueue = new ConcurrentLoopingQueue<Worker>(workers);
// Simulate async job dispatch
var jobTasks = new List<Task>();
for (int i = 0; i < 9; i++)
{
string job = $"Job-{i + 1}";
var worker = await workerQueue.NextAsync();
jobTasks.Add(worker.ProcessJobAsync(job));
}
await Task.WhenAll(jobTasks);
// Try to find a server by name
if (queue.TryGet(s => s.Hostname == "api-node-2", out var targetNode))
{
Console.WriteLine($"Found: {targetNode.Hostname}");
}
// Remove an offline server
queue.TryRemove(targetNode);
// Reset queue to start at beginning
queue.TryReset();
If you're using ConcurrentLoopingQueue<T> in a WPF UI context, pair it with
DCTekSolutions.SafeInvoker:
public class MyViewModel : DispatcherObject
{
private readonly IConcurrentLoopingQueue<JobItem> _jobQueue;
public MyViewModel(IConcurrentLoopingQueue<JobItem> jobQueue)
{
_jobQueue = jobQueue;
}
[SafeInvokeWPF]
public void ScheduleJob()
{
if (_jobQueue.TryNext(out var job))
{
// This safely runs on the UI thread
ProcessJob(job);
}
}
}
Or use the SafeInvoke extension directly:
this.SafeInvoke(vm =>
{
if (_jobQueue.TryNext(out var job))
vm.Execute(job);
});
SafeInvokerensures method calls that interact withDispatcherObjectare executed safely on the UI thread—especially important when consumingCycleKitqueues in ViewModels.