Наследование: IDisposable
        /// <summary>
        /// Push a new waiter into the waiter's stack
        /// </summary>
        /// <param name="newWaiterEntry">A waiter to put in the stack</param>
        public void PushWaiter(WaiterEntry newWaiterEntry)
        {
            // Remove the waiter if it is already in the stack and
            // update waiter's count as needed
            RemoveWaiter(newWaiterEntry, false);

            // If the stack is empty then newWaiterEntry is the new head of the stack
            if (null == _headWaiterEntry._nextWaiterEntry)
            {
                _headWaiterEntry._nextWaiterEntry = newWaiterEntry;
                newWaiterEntry._prevWaiterEntry   = _headWaiterEntry;
            }
            // If the stack is not empty then put newWaiterEntry as the new head
            // of the stack.
            else
            {
                // Save the old first waiter entry
                WaiterEntry oldFirstWaiterEntry = _headWaiterEntry._nextWaiterEntry;

                // Update the links
                _headWaiterEntry._nextWaiterEntry    = newWaiterEntry;
                newWaiterEntry._nextWaiterEntry      = oldFirstWaiterEntry;
                newWaiterEntry._prevWaiterEntry      = _headWaiterEntry;
                oldFirstWaiterEntry._prevWaiterEntry = newWaiterEntry;
            }

            // Increment the number of waiters
            ++_waitersCount;
        }
Пример #2
0
 public void CloseThreadWaiter()
 {
     if (_waiterEntry != null)
     {
         _waiterEntry.Close();
         _waiterEntry = null;
     }
 }
 /// <summary>
 /// Returns the WaiterEntry of the current thread
 /// </summary>
 /// <returns></returns>
 /// In order to avoid creation and destuction of WaiterEntry
 /// objects each thread has its own WaiterEntry object.
 private WaiterEntry GetThreadWaiterEntry()
 {
     if (null == _waiterEntry)
     {
         _waiterEntry = new WaiterEntry();
     }
     _waiterEntry.Reset();
     return(_waiterEntry);
 }
Пример #4
0
 /// <summary>
 /// Returns the WaiterEntry of the current thread
 /// </summary>
 /// <returns></returns>
 /// In order to avoid creation and destuction of WaiterEntry
 /// objects each thread has its own WaiterEntry object.
 private static WaiterEntry GetThreadWaiterEntry()
 {
     if (null == CurrentWaiterEntry)
     {
         CurrentWaiterEntry = new WaiterEntry();
     }
     CurrentWaiterEntry.Reset();
     return(CurrentWaiterEntry);
 }
Пример #5
0
 /// <summary>
 /// Returns the WaiterEntry of the current thread
 /// </summary>
 /// <returns></returns>
 /// In order to avoid creation and destuction of WaiterEntry
 /// objects each thread has its own WaiterEntry object.
 private static WaiterEntry GetThreadWaiterEntry()
 {
     if (_waiterEntry == null)
     {
         _waiterEntry = new WaiterEntry();
     }
     else
     {
         _waiterEntry.Reset();
     }
     return(_waiterEntry);
 }
Пример #6
0
        /// <summary>
        /// Pop a waiter from the waiter's stack
        /// </summary>
        /// <returns>Returns the first waiter in the stack</returns>
        private WaiterEntry PopWaiter()
        {
            WaiterEntry waiterEntry = this._headWaiterEntry._nextWaiterEntry;
            WaiterEntry entry2      = waiterEntry._nextWaiterEntry;

            this.RemoveWaiter(waiterEntry, true);
            this._headWaiterEntry._nextWaiterEntry = entry2;
            if (entry2 != null)
            {
                entry2._prevWaiterEntry = this._headWaiterEntry;
            }
            return(waiterEntry);
        }
Пример #7
0
 /// <summary>
 /// Push a new waiter into the waiter's stack
 /// </summary>
 /// <param name="newWaiterEntry">A waiter to put in the stack</param>
 public void PushWaiter(WaiterEntry newWaiterEntry)
 {
     this.RemoveWaiter(newWaiterEntry, false);
     if (this._headWaiterEntry._nextWaiterEntry == null)
     {
         this._headWaiterEntry._nextWaiterEntry = newWaiterEntry;
         newWaiterEntry._prevWaiterEntry        = this._headWaiterEntry;
     }
     else
     {
         WaiterEntry entry = this._headWaiterEntry._nextWaiterEntry;
         this._headWaiterEntry._nextWaiterEntry = newWaiterEntry;
         newWaiterEntry._nextWaiterEntry        = entry;
         newWaiterEntry._prevWaiterEntry        = this._headWaiterEntry;
         entry._prevWaiterEntry = newWaiterEntry;
     }
     this._waitersCount++;
 }
        /// <summary>
        /// Enqueue a work item to the queue.
        /// </summary>
        public bool EnqueueWorkItem(WorkItem workItem)
        {
            // A work item cannot be null, since null is used in the
            // WaitForWorkItem() method to indicate timeout or cancel
            if (null == workItem)
            {
                throw new ArgumentNullException("workItem", "workItem cannot be null");
            }

            bool enqueue = true;

            // First check if there is a waiter waiting for work item. During
            // the check, timed out waiters are ignored. If there is no
            // waiter then the work item is queued.
            lock (this)
            {
                ValidateNotDisposed();

                if (!_isWorkItemsQueueActive)
                {
                    return(false);
                }

                while (_waitersCount > 0)
                {
                    // Dequeue a waiter.
                    WaiterEntry waiterEntry = PopWaiter();

                    // Signal the waiter. On success break the loop
                    if (waiterEntry.Signal(workItem))
                    {
                        enqueue = false;
                        break;
                    }
                }

                if (enqueue)
                {
                    // Enqueue the work item
                    _workItems.Enqueue(workItem);
                }
            }
            return(true);
        }
        /// <summary>
        /// Remove a waiter from the stack
        /// </summary>
        /// <param name="waiterEntry">A waiter entry to remove</param>
        /// <param name="popDecrement">If true the waiter count is always decremented</param>
        private void RemoveWaiter(WaiterEntry waiterEntry, bool popDecrement)
        {
            // Store the prev entry in the list
            WaiterEntry prevWaiterEntry = waiterEntry._prevWaiterEntry;

            // Store the next entry in the list
            WaiterEntry nextWaiterEntry = waiterEntry._nextWaiterEntry;

            // A flag to indicate if we need to decrement the waiters count.
            // If we got here from PopWaiter then we must decrement.
            // If we got here from PushWaiter then we decrement only if
            // the waiter was already in the stack.
            bool decrementCounter = popDecrement;

            // Null the waiter's entry links
            waiterEntry._prevWaiterEntry = null;
            waiterEntry._nextWaiterEntry = null;

            // If the waiter entry had a prev link then update it.
            // It also means that the waiter is already in the list and we
            // need to decrement the waiters count.
            if (null != prevWaiterEntry)
            {
                prevWaiterEntry._nextWaiterEntry = nextWaiterEntry;
                decrementCounter = true;
            }

            // If the waiter entry had a next link then update it.
            // It also means that the waiter is already in the list and we
            // need to decrement the waiters count.
            if (null != nextWaiterEntry)
            {
                nextWaiterEntry._prevWaiterEntry = prevWaiterEntry;
                decrementCounter = true;
            }

            // Decrement the waiters count if needed
            if (decrementCounter)
            {
                --_waitersCount;
            }
        }
Пример #10
0
        /// <summary>
        /// Waits for a work item or exits on timeout or cancel
        /// </summary>
        /// <param name="millisecondsTimeout">Timeout in milliseconds</param>
        /// <param name="cancelEvent">Cancel wait handle</param>
        /// <returns>Returns true if the resource was granted</returns>
        public WorkItem DequeueWorkItem(int millisecondsTimeout, WaitHandle cancelEvent)
        {
            WaiterEntry newWaiterEntry = null;
            WorkItem    workItem       = null;

            lock (this)
            {
                this.ValidateNotDisposed();
                if (this._workItems.Count > 0)
                {
                    return(this._workItems.Dequeue() as WorkItem);
                }
                newWaiterEntry = this.GetThreadWaiterEntry();
                this.PushWaiter(newWaiterEntry);
            }
            WaitHandle[] waitHandles = new WaitHandle[] { newWaiterEntry.WaitHandle, cancelEvent };
            int          num         = WaitHandle.WaitAny(waitHandles, millisecondsTimeout, true);

            lock (this)
            {
                bool flag = 0 == num;
                if (!flag)
                {
                    bool flag2 = newWaiterEntry.Timeout();
                    if (flag2)
                    {
                        this.RemoveWaiter(newWaiterEntry, false);
                    }
                    flag = !flag2;
                }
                if (flag)
                {
                    workItem = newWaiterEntry.WorkItem;
                    if (workItem == null)
                    {
                        workItem = this._workItems.Dequeue() as WorkItem;
                    }
                }
            }
            return(workItem);
        }
Пример #11
0
        /// <summary>
        /// Pop a waiter from the waiter's stack
        /// </summary>
        /// <returns>Returns the first waiter in the stack</returns>
        private WaiterEntry PopWaiter()
        {
            // Store the current stack head
            WaiterEntry oldFirstWaiterEntry = _headWaiterEntry._nextWaiterEntry;

            // Store the new stack head
            WaiterEntry newHeadWaiterEntry = oldFirstWaiterEntry._nextWaiterEntry;

            // Update the old stack head list links and decrement the number
            // waiters.
            RemoveWaiter(oldFirstWaiterEntry, true);

            // Update the new stack head
            _headWaiterEntry._nextWaiterEntry = newHeadWaiterEntry;
            if (null != newHeadWaiterEntry)
            {
                newHeadWaiterEntry._prevWaiterEntry = _headWaiterEntry;
            }

            // Return the old stack head
            return(oldFirstWaiterEntry);
        }
Пример #12
0
        /// <summary>
        /// Remove a waiter from the stack
        /// </summary>
        /// <param name="waiterEntry">A waiter entry to remove</param>
        /// <param name="popDecrement">If true the waiter count is always decremented</param>
        private void RemoveWaiter(WaiterEntry waiterEntry, bool popDecrement)
        {
            WaiterEntry entry  = waiterEntry._prevWaiterEntry;
            WaiterEntry entry2 = waiterEntry._nextWaiterEntry;
            bool        flag   = popDecrement;

            waiterEntry._prevWaiterEntry = null;
            waiterEntry._nextWaiterEntry = null;
            if (entry != null)
            {
                entry._nextWaiterEntry = entry2;
                flag = true;
            }
            if (entry2 != null)
            {
                entry2._prevWaiterEntry = entry;
                flag = true;
            }
            if (flag)
            {
                this._waitersCount--;
            }
        }
Пример #13
0
        /// <summary>
        /// Cleanup the work items queue, hence no more work
        /// items are allowed to be queue
        /// </summary>
        protected virtual void Cleanup()
        {
            lock (this)
            {
                // Deactivate only once
                if (!_isWorkItemsQueueActive)
                {
                    return;
                }

                // Don't queue more work items
                _isWorkItemsQueueActive = false;

                foreach (WorkItem workItem in _workItems)
                {
                    workItem.DisposeOfState();
                }

                // Clear the work items that are already queued
                _workItems.Clear();

                // Note:
                // I don't iterate over the queue and dispose of work items's states,
                // since if a work item has a state object that is still in use in the
                // application then I must not dispose it.

                // Tell the waiters that they were timed out.
                // It won't signal them to exit, but to ignore their
                // next work item.
                while (_waitersCount > 0)
                {
                    WaiterEntry waiterEntry = PopWaiter();
                    waiterEntry.Timeout();
                }
            }
        }
Пример #14
0
        /// <summary>
        /// Waits for a work item or exits on timeout or cancel
        /// </summary>
        /// <param name="millisecondsTimeout">Timeout in milliseconds</param>
        /// <param name="cancelEvent">Cancel wait handle</param>
        /// <returns>Returns true if the resource was granted</returns>
        public WorkItem DequeueWorkItem(
            int millisecondsTimeout,
            WaitHandle cancelEvent)
        {
            /// This method cause the caller to wait for a work item.
            /// If there is at least one waiting work item then the
            /// method returns immidiately with true.
            ///
            /// If there are no waiting work items then the caller
            /// is queued between other waiters for a work item to arrive.
            ///
            /// If a work item didn't come within millisecondsTimeout or
            /// the user canceled the wait by signaling the cancelEvent
            /// then the method returns false to indicate that the caller
            /// didn't get a work item.

            WaiterEntry waiterEntry = null;
            WorkItem    workItem    = null;

            lock (this)
            {
                ValidateNotDisposed();

                // If there are waiting work items then take one and return.
                if (_workItems.Count > 0)
                {
                    workItem = _workItems.Dequeue() as WorkItem;
                    return(workItem);
                }
                // No waiting work items ...
                else
                {
                    // Get the wait entry for the waiters queue
                    waiterEntry = GetThreadWaiterEntry();

                    // Put the waiter with the other waiters
                    PushWaiter(waiterEntry);
                }
            }

            // Prepare array of wait handle for the WaitHandle.WaitAny()
            WaitHandle [] waitHandles = new WaitHandle [] {
                waiterEntry.WaitHandle,
                cancelEvent
            };

            // Wait for an available resource, cancel event, or timeout.

            // During the wait we are supposes to exit the synchronization
            // domain. (Placing true as the third argument of the WaitAny())
            // It just doesn't work, I don't know why, so I have lock(this)
            // statments insted of one.

            int index = WaitHandle.WaitAny(
                waitHandles,
                millisecondsTimeout,
                true);

            lock (this)
            {
                // success is true if it got a work item.
                bool success = (0 == index);

                // The timeout variable is used only for readability.
                // (We treat cancel as timeout)
                bool timeout = !success;

                // On timeout update the waiterEntry that it is timed out
                if (timeout)
                {
                    // The Timeout() fails if the waiter has already been signaled
                    timeout = waiterEntry.Timeout();

                    // On timeout remove the waiter from the queue.
                    // Note that the complexity is O(1).
                    if (timeout)
                    {
                        RemoveWaiter(waiterEntry, false);
                    }

                    // Again readability
                    success = !timeout;
                }

                // On success return the work item
                if (success)
                {
                    workItem = waiterEntry.WorkItem;

                    if (null == workItem)
                    {
                        workItem = _workItems.Dequeue() as WorkItem;
                    }
                }
            }
            // On failure return null.
            return(workItem);
        }
Пример #15
0
        /// <summary>
        /// Push a new waiter into the waiter's stack
        /// </summary>
        /// <param name="newWaiterEntry">A waiter to put in the stack</param>
        public void PushWaiter(WaiterEntry newWaiterEntry)
        {
            // Remove the waiter if it is already in the stack and
            // update waiter's count as needed
            RemoveWaiter(newWaiterEntry, false);

            // If the stack is empty then newWaiterEntry is the new head of the stack
            if (null == _headWaiterEntry._nextWaiterEntry)
            {
                _headWaiterEntry._nextWaiterEntry = newWaiterEntry;
                newWaiterEntry._prevWaiterEntry = _headWaiterEntry;

            }
            // If the stack is not empty then put newWaiterEntry as the new head
            // of the stack.
            else
            {
                // Save the old first waiter entry
                WaiterEntry oldFirstWaiterEntry = _headWaiterEntry._nextWaiterEntry;

                // Update the links
                _headWaiterEntry._nextWaiterEntry = newWaiterEntry;
                newWaiterEntry._nextWaiterEntry = oldFirstWaiterEntry;
                newWaiterEntry._prevWaiterEntry = _headWaiterEntry;
                oldFirstWaiterEntry._prevWaiterEntry = newWaiterEntry;
            }

            // Increment the number of waiters
            ++_waitersCount;
        }
Пример #16
0
 /// <summary>
 /// Returns the WaiterEntry of the current thread
 /// </summary>
 /// <returns></returns>
 /// In order to avoid creation and destuction of WaiterEntry
 /// objects each thread has its own WaiterEntry object.
 private WaiterEntry GetThreadWaiterEntry()
 {
     if (null == _waiterEntry)
     {
         _waiterEntry = new WaiterEntry();
     }
     _waiterEntry.Reset();
     return _waiterEntry;
 }
Пример #17
0
        /// <summary>
        /// Remove a waiter from the stack
        /// </summary>
        /// <param name="waiterEntry">A waiter entry to remove</param>
        /// <param name="popDecrement">If true the waiter count is always decremented</param>
        private void RemoveWaiter(WaiterEntry waiterEntry, bool popDecrement)
        {
            // Store the prev entry in the list
            WaiterEntry prevWaiterEntry = waiterEntry._prevWaiterEntry;

            // Store the next entry in the list
            WaiterEntry nextWaiterEntry = waiterEntry._nextWaiterEntry;

            // A flag to indicate if we need to decrement the waiters count.
            // If we got here from PopWaiter then we must decrement.
            // If we got here from PushWaiter then we decrement only if
            // the waiter was already in the stack.
            bool decrementCounter = popDecrement;

            // Null the waiter's entry links
            waiterEntry._prevWaiterEntry = null;
            waiterEntry._nextWaiterEntry = null;

            // If the waiter entry had a prev link then update it.
            // It also means that the waiter is already in the list and we
            // need to decrement the waiters count.
            if (null != prevWaiterEntry)
            {
                prevWaiterEntry._nextWaiterEntry = nextWaiterEntry;
                decrementCounter = true;
            }

            // If the waiter entry had a next link then update it.
            // It also means that the waiter is already in the list and we
            // need to decrement the waiters count.
            if (null != nextWaiterEntry)
            {
                nextWaiterEntry._prevWaiterEntry = prevWaiterEntry;
                decrementCounter = true;
            }

            // Decrement the waiters count if needed
            if (decrementCounter)
            {
                --_waitersCount;
            }
        }