public void QueueWorkItem([NotNull][Pooled] Action workItem) { var lockTaken = false; try { spinLock.Enter(ref lockTaken); PooledDelegateHelper.AddReference(workItem); workItems.Enqueue(workItem); workAvailable.Set(); var curWorkingCount = Interlocked.CompareExchange(ref workingCount, 0, 0); if (curWorkingCount + 1 >= aliveCount && aliveCount < maxThreadCount) { aliveCount++; Task.Factory.StartNew(ProcessWorkItems, TaskCreationOptions.LongRunning); } } finally { if (lockTaken) { spinLock.Exit(true); } } }
public void QueueWorkItem([NotNull][Pooled] Action workItem) { var lockTaken = false; try { spinLock.Enter(ref lockTaken); PooledDelegateHelper.AddReference(workItem); workItems.Enqueue(workItem); if (activeThreadCount + 1 >= workers.Count && workers.Count < maxThreadCount) { var worker = Task.Factory.StartNew(ProcessWorkItems, workers.Count, TaskCreationOptions.LongRunning); workers.Add(worker); //Console.WriteLine($"Thread {workers.Count} added"); } workAvailable.Set(); } finally { if (lockTaken) { spinLock.Exit(true); } } }
public void QueueWorkItem([NotNull][Pooled] Action workItem) { PooledDelegateHelper.AddReference(workItem); bool lockTaken = false; bool startNewTask = false; try { spinLock.Enter(ref lockTaken); workItems.Enqueue(workItem); workAvailable.Set(); var curWorkingCount = Interlocked.CompareExchange(ref workingCount, 0, 0); if (curWorkingCount + 1 >= aliveCount && aliveCount < maxThreadCount) { startNewTask = true; aliveCount++; } } finally { if (lockTaken) { spinLock.Exit(true); } } // No point in wasting spins on the lock while creating the task if (startNewTask) { new Task(cachedTaskLoop, null, TaskCreationOptions.LongRunning).Start(); } }
private void ProcessWorkItems(object state) { long lastWork = Stopwatch.GetTimestamp(); TimeSpan maxIdleTime = TimeSpan.FromTicks(MaxIdleTimeInTicks); while (true) { Action workItem = null; var lockTaken = false; bool idleForTooLong = Utilities.ConvertRawToTimestamp(Stopwatch.GetTimestamp() - lastWork) < maxIdleTime; try { spinLock.Enter(ref lockTaken); if (workItems.Count > 0) { workItem = workItems.Dequeue(); if (workItems.Count == 0) { workAvailable.Reset(); } } else if (idleForTooLong) { aliveCount--; return; } } finally { if (lockTaken) { spinLock.Exit(true); } } if (workItem != null) { Interlocked.Increment(ref workingCount); try { workItem.Invoke(); } catch (Exception) { // Ignoring Exception } Interlocked.Decrement(ref workingCount); PooledDelegateHelper.Release(workItem); lastWork = Stopwatch.GetTimestamp(); } // Wait for another work item to be (potentially) available workAvailable.WaitOne(maxIdleTime); } }
public void QueueWorkItem([NotNull, Pooled] Action workItem) { // Throw right here to help debugging if (workItem == null) { throw new NullReferenceException(nameof(workItem)); } PooledDelegateHelper.AddReference(workItem); LinkedWork newSharedNode = null; while (true) { // Are all threads busy ? LinkedIdleThread node = idleThreads; if (node == null) { if (newSharedNode == null) { newSharedNode = new LinkedWork(workItem); if (idleThreads != null) { continue; } } // Schedule it on the shared stack newSharedNode.Previous = Interlocked.Exchange(ref sharedWorkStack, newSharedNode); newSharedNode.PreviousIsValid = true; break; } // Schedule this work item on latest idle thread while (node.PreviousIsValid == false) { // Spin while invalid, should be extremely short } // Try take this thread if (Interlocked.CompareExchange(ref idleThreads, node.Previous, node) != node) { continue; // Latest idle threads changed, try again } // Wakeup thread and schedule work // The order those two lines are laid out in is essential ! Interlocked.Exchange(ref node.Work, workItem); node.MRE.Set(); break; } }
private void ProcessWorkItems() { while (true) { Action workItem = null; var lockTaken = false; try { spinLock.Enter(ref lockTaken); int workItemCount = workItems.Count; if (workItemCount > 0) { workItem = workItems.Dequeue(); if (workItemCount == 1) { workAvailable.Reset(); // we must have taken off our last item } } } finally { if (lockTaken) { spinLock.Exit(true); } } if (workItem != null) { Interlocked.Increment(ref workingCount); try { workItem.Invoke(); } catch (Exception) { // Ignoring Exception } Interlocked.Decrement(ref workingCount); PooledDelegateHelper.Release(workItem); } // Wait for another work item to be (potentially) available if (workAvailable.WaitOne(maxIdleTime) == false) { aliveCount--; return; } } }
private void ProcessWorkItems() { while (true) { Action workItem = null; var lockTaken = false; int workItemCount; try { spinLock.Enter(ref lockTaken); workItemCount = workItems.Count; if (workItemCount > 0) { workItem = workItems.Dequeue(); } } finally { if (lockTaken) { spinLock.Exit(true); } } // do we have a job to do? if (workItem != null) { try { workItem.Invoke(); } catch (Exception) { // Ignoring Exception } PooledDelegateHelper.Release(workItem); } // only reset and wait if we took our last job if (workItemCount <= 1) { workAvailable.WaitOne(); } } }
private void ProcessWorkItems() { while (true) { Action workItem = null; var lockTaken = false; try { spinLock.Enter(ref lockTaken); if (workItems.Count > 0) { workItem = workItems.Dequeue(); } } finally { if (lockTaken) { spinLock.Exit(true); } } // do we have a job to do? if (workItem != null) { try { workItem.Invoke(); } catch (Exception) { // Ignoring Exception } PooledDelegateHelper.Release(workItem); } // couldn't find work, wait until some more is available else { workAvailable.WaitOne(); } } }
public void QueueWorkItem([NotNull][Pooled] Action workItem) { PooledDelegateHelper.AddReference(workItem); bool lockTaken = false; try { spinLock.Enter(ref lockTaken); workItems.Enqueue(workItem); } finally { if (lockTaken) { spinLock.Exit(true); } } workAvailable.Set(); }
public void QueueWorkItem([NotNull][Pooled] Action workItem) { bool lockTaken = false; bool startNewTask = false; PooledDelegateHelper.AddReference(workItem); try { spinLock.Enter(ref lockTaken); workItems.Enqueue(workItem); workAvailable.Set(); // We're only locking when potentially increasing aliveCount as we // don't want to go above our maximum amount of threads. int curBusyCount = Interlocked.CompareExchange(ref busyCount, 0, 0); int curAliveCount = Interlocked.CompareExchange(ref aliveCount, 0, 0); if (curBusyCount + 1 >= curAliveCount && curAliveCount < maxThreadCount) { // Start threads as busy otherwise only one thread will be created // when calling this function multiple times in a row Interlocked.Increment(ref busyCount); Interlocked.Increment(ref aliveCount); startNewTask = true; } } finally { if (lockTaken) { spinLock.Exit(true); } } // No point in wasting spins on the lock while creating the task if (startNewTask) { new Task(cachedTaskLoop, null, TaskCreationOptions.LongRunning).Start(); } }
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() { Interlocked.Decrement(ref busyCount); try { long lastWorkTS = Stopwatch.GetTimestamp(); while (true) { Action workItem = null; bool lockTaken = false; try { spinLock.Enter(ref lockTaken); if (workItems.Count > 0) { workItem = workItems.Dequeue(); if (workItems.Count == 0) { workAvailable.Reset(); } } } finally { if (lockTaken) { spinLock.Exit(true); } } if (workItem == null) { bool idleForTooLong = Stopwatch.GetTimestamp() - lastWorkTS > MaxIdleTimeTS; // Wait for another work item to be (potentially) available if (idleForTooLong || workAvailable.WaitOne(MaxIdleTimeInMS) == false) { // No work given in the last MaxIdleTimeTS, close this task return; } } else { Interlocked.Increment(ref busyCount); try { workItem(); } // Let exceptions fall into unhandled as we don't have any // good mechanisms to pass it elegantly over to user-land yet finally { Interlocked.Decrement(ref busyCount); } PooledDelegateHelper.Release(workItem); lastWorkTS = Stopwatch.GetTimestamp(); } } } finally { Interlocked.Decrement(ref aliveCount); } }
private void ProcessWorkItems(object state) { //var spinWait = new SpinWait(); while (true) { Action workItem = null; //while (!spinWait.NextSpinWillYield) { var lockTaken = false; try { spinLock.Enter(ref lockTaken); if (workItems.Count > 0) { try { workItem = workItems.Dequeue(); //Interlocked.Increment(ref activeThreadCount); if (workItems.Count == 0) { workAvailable.Reset(); } } catch { } } //if (workItems.Count > 0) //{ // // If we didn't consume the last work item, kick off another worker // workAvailable.Set(); //} } finally { if (lockTaken) { spinLock.Exit(true); } } if (workItem != null) { try { Interlocked.Increment(ref activeThreadCount); workItem.Invoke(); //spinWait.Reset(); } catch (Exception) { // Ignoring Exception } finally { PooledDelegateHelper.Release(workItem); Interlocked.Decrement(ref activeThreadCount); } } else { //spinWait.SpinOnce(); } } // Wait for another work item to be (potentially) available workAvailable.WaitOne(); } }
private void ProcessWorkItems(object nodeObj) { // nodeObj is non-null when a thread caught an exception and had to throw, // the thread created another one and passed its node obj to us. LinkedIdleThread node = nodeObj == null ? new LinkedIdleThread(new ManualResetEventSlim(true)) : (LinkedIdleThread)nodeObj; try { while (true) { Action action; LinkedWork workNode = sharedWorkStack; if (workNode != null) { if (TryTakeFromSharedNonBlocking(out var tempAction, workNode)) { action = tempAction; } else { // We have shared work to do but failed to retrieve it, try again continue; } } else { // Should we notify system that this thread is ready to work? // This has to also work for when a thread takes the place of another one when restoring // from an exception for example. // If the mre was set and we took the work, this node definitely is dequeued, re-queue it if (node.MRE.IsSet && Volatile.Read(ref node.Work) == null) { // Notify that we're waiting for work node.MRE.Reset(); node.PreviousIsValid = false; node.Previous = Interlocked.Exchange(ref idleThreads, node); node.PreviousIsValid = true; } // Wait for work SpinWait sw = new SpinWait(); while (true) { if (node.MRE.IsSet) { // Work has been scheduled for this thread specifically, take it action = Interlocked.Exchange(ref node.Work, null); break; } if (TryTakeFromSharedNonBlocking(out var tempAction, sharedWorkStack)) { action = tempAction; break; // We successfully dequeued this node from the shared stack, quit loop and process action } // Wait for work if (sw.NextSpinWillYield) { // Wait for work to be scheduled specifically to this thread node.MRE.Wait(); action = Interlocked.Exchange(ref node.Work, null); break; } sw.SpinOnce(); } } 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(node); } }
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(); } }