private bool TryDequeue(WorkQueueLocals locals, out IThreadPoolWorkItem callback, out bool missedSteal) { var localQueue = locals.Queue; missedSteal = false; if ((callback = localQueue.LocalPop()) == null && // first try the local queue !_queue.TryDequeue(out callback)) // then try the global queue { // finally try to steal from another thread's local queue var queues = Volatile.Read(ref _localQueues); int c = queues.Length; int maxIndex = c - 1; int i = locals.Random.Next(c); while (c > 0) { i = i < maxIndex ? i + 1 : 0; var otherQueue = queues[i]; if (otherQueue != localQueue && otherQueue.CanSteal) { callback = otherQueue.TrySteal(ref missedSteal); if (callback != null) { break; } } c--; } } return(callback != null); }
public IEnumerable <IThreadPoolWorkItem> GetConsumingEnumerable() { using (var locals = new WorkQueueLocals(ref _localQueues)) { _localQueue = locals.Queue; while (true) { IThreadPoolWorkItem work; if (TryDequeue(locals, out work, out var missedSteal)) { yield return(work); } else if (IsAddingCompleted) { while (TryDequeue(locals, out work, out missedSteal)) { yield return(work); } break; } else { if (missedSteal) { EnsureThreadRequested(); } _semaphore.Wait(); MarkThreadRequestSatisfied(); } } } }
public void Dispatch(Action <TWorkItem, CancellationToken> action, CancellationToken cancellationToken) { using var locals = new WorkQueueLocals(this); try { CustomWorkQueueNonGenericStore.LocalQueue = locals.Queue; var waitAdded = false; var spinWait = new SpinWait(); while (!cancellationToken.IsCancellationRequested) { if (TryDequeue(locals, out var work, out var missedSteal)) { if (!waitAdded) { SignalOneThread(); } do { action(work, cancellationToken); } while (TryDequeue(locals, out work, out missedSteal)); } if (!waitAdded) { AddWaitNode(locals.WaitNode, ref spinWait); waitAdded = true; continue; } if (missedSteal) { spinWait.SpinOnce(); continue; } locals.Semaphore.Wait(cancellationToken); spinWait.Reset(); waitAdded = false; } cancellationToken.ThrowIfCancellationRequested(); } finally { CustomWorkQueueNonGenericStore.LocalQueue = null; } }
public async Task DispatchAsync(Func<TWorkItem, CancellationToken, Task> action, CancellationToken cancellationToken) { using var locals = new WorkQueueLocals(this); try { LocalQueue.Value = locals.Queue; var waitAdded = false; var spinWait = new SpinWait(); while (!cancellationToken.IsCancellationRequested) { if (TryDequeue(locals, out var work, out var missedSteal)) { if (!waitAdded) SignalOneThread(); do { await action(work, cancellationToken); } while (TryDequeue(locals, out work, out missedSteal)); } if (!waitAdded) { AddWaitNode(locals.WaitNode, ref spinWait); waitAdded = true; continue; } if (missedSteal) { spinWait.SpinOnce(); continue; } await locals.Semaphore.WaitAsync(cancellationToken); spinWait.Reset(); waitAdded = false; } cancellationToken.ThrowIfCancellationRequested(); } finally { LocalQueue.Value = null; } }