예제 #1
0
        /// <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);
        }
예제 #2
0
        /// <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();
            }
        }