/// <summary> /// Adds an action to the work queue to run on one of the available threads. /// </summary> /// <param name="workItem">The action that represents the work item to execute.</param> /// <param name="amount">Specifies how many times to execute the <paramref name="workItem"/>.</param> /// <remarks> /// It is strongly recommended that the action takes less than a millisecond. /// </remarks> public void QueueWorkItem([NotNull, Pooled] Action workItem, int amount = 1) { // Throw right here to help debugging if (workItem is null) { throw new NullReferenceException(nameof(workItem)); } if (amount < 1) { throw new ArgumentOutOfRangeException(nameof(amount)); } if (disposing > 0) { throw new ObjectDisposedException(ToString()); } Interlocked.Add(ref workScheduled, amount); for (int i = 0; i < amount; i++) { PooledDelegateHelper.AddReference(workItem); workItems.Enqueue(workItem); } semaphore.Release(amount); }
/// <summary> /// Attempt to steal work from the threadpool to execute it from the calling thread. /// If you absolutely have to block inside one of the threadpool's thread for whatever /// reason do a busy loop over this function. /// </summary> public bool TryCooperate() { if (workItems.TryDequeue(out var workItem)) { Interlocked.Increment(ref threadsBusy); Interlocked.Decrement(ref workScheduled); try { workItem.Invoke(); } finally { PooledDelegateHelper.Release(workItem); Interlocked.Decrement(ref threadsBusy); Interlocked.Increment(ref completionCounter); } return(true); } return(false); }
public void QueueWorkItem([NotNull, Pooled] Action workItem, int amount = 1) { // Throw right here to help debugging if (workItem == null) { throw new NullReferenceException(nameof(workItem)); } if (amount < 1) { throw new ArgumentOutOfRangeException(nameof(amount)); } Interlocked.Add(ref itemCount, amount); for (int i = 0; i < amount; i++) { PooledDelegateHelper.AddReference(workItem); queue.Enqueue(workItem); } if (Volatile.Read(ref idleCount) == 0) { return; } lock (lockObj) { if (Volatile.Read(ref idleCount) == 0) { return; } Monitor.Pulse(lockObj); } }
private void ProcessWorkItems(object paramObj) { try { while (true) { Action action; var sw = new SpinWait(); while (true) { if (queue.TryDequeue(out action)) { break; } if (Volatile.Read(ref itemCount) == 0) { if (sw.NextSpinWillYield) { bool reset = false; lock (lockObj) { if (Volatile.Read(ref itemCount) == 0) { Interlocked.Increment(ref idleCount); Monitor.Wait(lockObj); // We've got work to deal with, pulse other threads Monitor.Pulse(lockObj); reset = true; } } if (reset) { Interlocked.Decrement(ref idleCount); sw = new SpinWait(); } } else { // Spin for a while to catch more incoming work sw.SpinOnce(); } } } Interlocked.Decrement(ref itemCount); try { action(); } finally { PooledDelegateHelper.Release(action); } } } finally { // We must keep up the amount of threads that the system handles. // Spawn a new one as this one is about to abort because of an exception. NewThread(); } }