Example #1
0
        /// <summary>
        /// Dequeue a WorkItem for processing
        /// </summary>
        /// <returns>A WorkItem or null if the queue has stopped</returns>
        public WorkItem Dequeue()
        {
            SpinWait sw = new SpinWait();

            do
            {
                WorkItemQueueState cachedState = State;

                if (cachedState == WorkItemQueueState.Stopped)
                {
                    return(null); // Tell worker to terminate
                }
                int cachedRemoveId = _removeId;
                int cachedAddId    = _addId;

                // Empty case (or paused)
                if (cachedRemoveId == cachedAddId || cachedState == WorkItemQueueState.Paused)
                {
                    // Spin a few times to see if something changes
                    if (sw.Count <= spinCount)
                    {
                        sw.SpinOnce();
                    }
                    else
                    {
                        // Reset to wait for an enqueue
                        _mreAdd.Reset();

                        // Recheck for an enqueue to avoid a Wait
                        if ((cachedRemoveId != _removeId || cachedAddId != _addId) && cachedState != WorkItemQueueState.Paused)
                        {
                            // Queue is not empty, set the event
                            _mreAdd.Set();
                            continue;
                        }

                        // Wait for something to happen
                        _mreAdd.Wait(500);
                    }

                    continue;
                }

                // Validate that we are the current dequeuer
                if (Interlocked.CompareExchange(ref _removeId, cachedRemoveId + 1, cachedRemoveId) != cachedRemoveId)
                {
                    continue;
                }


                // Dequeue our work item
                WorkItem work;
                while (!_innerQueue.TryDequeue(out work))
                {
                }
                ;

                // Add to items processed using CAS
                Interlocked.Increment(ref _itemsProcessed);

                return(work);
            } while (true);
        }
Example #2
0
        /// <summary>
        /// Removes the first element from the queue and returns it (or <c>null</c>).
        /// </summary>
        /// <param name="blockWhenEmpty">
        /// If <c>true</c> and the queue is empty, the calling thread is blocked until
        /// either an element is enqueued, or <see cref="Stop"/> is called.
        /// </param>
        /// <returns>
        /// <list type="bullet">
        ///   <item>
        ///     <term>If the queue not empty</term>
        ///     <description>the first element.</description>
        ///   </item>
        ///   <item>
        ///     <term>otherwise, if <paramref name="blockWhenEmpty"/>==<c>false</c>
        ///       or <see cref="Stop"/> has been called</term>
        ///     <description><c>null</c>.</description>
        ///   </item>
        /// </list>
        /// </returns>
        public Event Dequeue(bool blockWhenEmpty)
        {
            SpinWait sw = new SpinWait();

            do
            {
                int cachedRemoveId = _removeId;
                int cachedAddId    = _addId;

                // Empty case
                if (cachedRemoveId == cachedAddId)
                {
                    if (!blockWhenEmpty || _stopped != 0)
                    {
                        return(null);
                    }

                    // Spin a few times to see if something changes
                    if (sw.Count <= spinCount)
                    {
                        sw.SpinOnce();
                    }
                    else
                    {
                        // Reset to wait for an enqueue
                        _mreAdd.Reset();

                        // Recheck for an enqueue to avoid a Wait
                        if (cachedRemoveId != _removeId || cachedAddId != _addId)
                        {
                            // Queue is not empty, set the event
                            _mreAdd.Set();
                            continue;
                        }

                        // Wait for something to happen
                        _mreAdd.Wait(500);
                    }

                    continue;
                }

                // Validate that we are the current dequeuer
                if (Interlocked.CompareExchange(ref _removeId, cachedRemoveId + 1, cachedRemoveId) != cachedRemoveId)
                {
                    continue;
                }


                // Dequeue our work item
                Event e;
                while (!_queue.TryDequeue(out e))
                {
                    if (!blockWhenEmpty || _stopped != 0)
                    {
                        return(null);
                    }
                }

                return(e);
            } while (true);
        }