public void AddQueueWaitNode(QueueEntry entry, InMemoryQueueWaitNode node) { var headNext = node.Next = null; var spinWait = new SpinWait(); while (true) { var newNext = Interlocked.CompareExchange(ref entry.WaitHead.Next, node, headNext); if (newNext == headNext) { break; } headNext = node.Next = newNext; spinWait.SpinOnce(); } }
public override IFetchedJob FetchNextJob(string[] queueNames, CancellationToken cancellationToken) { using (var ready = new SemaphoreSlim(0, queueNames.Length)) { var waitNode = new InMemoryQueueWaitNode(ready); var waitAdded = false; while (!cancellationToken.IsCancellationRequested) { // TODO: Ensure duplicate queue names do not fail everything var entries = _dispatcher.GetOrAddQueues(queueNames); foreach (var entry in entries) { if (entry.Value.Queue.TryDequeue(out var jobId)) { _dispatcher.SignalOneQueueWaitNode(entry.Value); return(new InMemoryFetchedJob(_dispatcher, entry.Key, jobId)); } } if (!waitAdded && ready.CurrentCount == 0) { foreach (var entry in entries) { _dispatcher.AddQueueWaitNode(entry.Value, waitNode); } waitAdded = true; continue; } ready.Wait(cancellationToken); waitAdded = false; } } cancellationToken.ThrowIfCancellationRequested(); return(null); }