예제 #1
0
        /// <summary>
        /// Waits for any of the work items in the specified array to complete, cancel, or timeout
        /// </summary>
        /// <param name="waitableResults">Array of work item result objects</param>
        /// <param name="millisecondsTimeout">The number of milliseconds to wait, or Timeout.Infinite (-1) to wait indefinitely.</param>
        /// <param name="exitContext">
        /// true to exit the synchronization domain for the context before the wait (if in a synchronized context), and reacquire it; otherwise, false.
        /// </param>
        /// <param name="cancelWaitHandle">A cancel wait handle to interrupt the wait if needed</param>
        /// <returns>
        /// The array index of the work item result that satisfied the wait, or WaitTimeout if no work item result satisfied the wait and a time interval equivalent to millisecondsTimeout has passed or the work item has been canceled.
        /// </returns>
        internal static int WaitAny(
            IWaitableResult[] waitableResults,
            int millisecondsTimeout,
            bool exitContext,
            WaitHandle cancelWaitHandle)
        {
            WaitHandle[] waitHandles;

            if (null != cancelWaitHandle)
            {
                waitHandles = new WaitHandle[waitableResults.Length + 1];
                GetWaitHandles(waitableResults, waitHandles);
                waitHandles[waitableResults.Length] = cancelWaitHandle;
            }
            else
            {
                waitHandles = new WaitHandle[waitableResults.Length];
                GetWaitHandles(waitableResults, waitHandles);
            }

            int result = CTPEventWaitHandle.WaitAny(waitHandles, millisecondsTimeout, exitContext);

            // Treat cancel as timeout
            if (null != cancelWaitHandle)
            {
                if (result == waitableResults.Length)
                {
                    result = CTPEventWaitHandle.WaitTimeout;
                }
            }

            ReleaseWaitHandles(waitableResults);

            return(result);
        }
예제 #2
0
        /// <summary>
        /// Get the result of the work item.
        /// If the work item didn't run yet then the caller waits for the result, timeout, or cancel.
        /// In case of error the e argument is filled with the exception
        /// </summary>
        /// <returns>The result of the work item</returns>
        private object GetResult(
            int millisecondsTimeout,
            bool exitContext,
            WaitHandle cancelWaitHandle,
            out Exception e)
        {
            e = null;

            // Check for cancel
            if (WorkItemState.Canceled == GetWorkItemState())
            {
                throw new WorkItemCancelException("Work item canceled");
            }

            // Check for completion
            if (IsCompleted)
            {
                e = _exception;
                return(_result);
            }

            // If no cancelWaitHandle is provided
            if (null == cancelWaitHandle)
            {
                WaitHandle wh = GetWaitHandle();

                bool timeout = !CTPEventWaitHandle.WaitOne(wh, millisecondsTimeout, exitContext);

                ReleaseWaitHandle();

                if (timeout)
                {
                    throw new WorkItemTimeoutException("Work item timeout");
                }
            }
            else
            {
                WaitHandle wh     = GetWaitHandle();
                int        result = CTPEventWaitHandle.WaitAny(new WaitHandle[] { wh, cancelWaitHandle });
                ReleaseWaitHandle();

                switch (result)
                {
                case 0:
                    // The work item signaled
                    // Note that the signal could be also as a result of canceling the
                    // work item (not the get result)
                    break;

                case 1:
                case CTPEventWaitHandle.WaitTimeout:
                    throw new WorkItemTimeoutException("Work item timeout");

                default:
                    Debug.Assert(false);
                    break;
                }
            }

            // Check for cancel
            if (WorkItemState.Canceled == GetWorkItemState())
            {
                throw new WorkItemCancelException("Work item canceled");
            }

            Debug.Assert(IsCompleted);

            e = _exception;

            // Return the result
            return(_result);
        }
예제 #3
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 it.
            //
            // 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 null to indicate that the caller
            // didn't get a work item.

            WaiterEntry waiterEntry;
            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 ...

                // Get the waiter 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 two lock(this)
            // statments instead of one.

            int index = CTPEventWaitHandle.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);
        }
예제 #4
0
        /// <summary>
        /// Wait for all work items to complete
        /// </summary>
        /// <param name="waitableResults">Array of work item result objects</param>
        /// <param name="millisecondsTimeout">The number of milliseconds to wait, or Timeout.Infinite (-1) to wait indefinitely.</param>
        /// <param name="exitContext">
        /// true to exit the synchronization domain for the context before the wait (if in a synchronized context), and reacquire it; otherwise, false.
        /// </param>
        /// <param name="cancelWaitHandle">A cancel wait handle to interrupt the wait if needed</param>
        /// <returns>
        /// true when every work item in waitableResults has completed; otherwise false.
        /// </returns>
        internal static bool WaitAll(
            IWaitableResult[] waitableResults,
            int millisecondsTimeout,
            bool exitContext,
            WaitHandle cancelWaitHandle)
        {
            if (0 == waitableResults.Length)
            {
                return(true);
            }

            bool success;

            WaitHandle[] waitHandles = new WaitHandle[waitableResults.Length];
            GetWaitHandles(waitableResults, waitHandles);

            if ((null == cancelWaitHandle) && (waitHandles.Length <= 64))
            {
                success = CTPEventWaitHandle.WaitAll(waitHandles, millisecondsTimeout, exitContext);
            }
            else
            {
                success = true;
                int       millisecondsLeft = millisecondsTimeout;
                Stopwatch stopwatch        = Stopwatch.StartNew();

                WaitHandle[] whs;
                if (null != cancelWaitHandle)
                {
                    whs = new WaitHandle[] { null, cancelWaitHandle };
                }
                else
                {
                    whs = new WaitHandle[] { null };
                }

                bool waitInfinitely = (Timeout.Infinite == millisecondsTimeout);
                // Iterate over the wait handles and wait for each one to complete.
                // We cannot use WaitHandle.WaitAll directly, because the cancelWaitHandle
                // won't affect it.
                // Each iteration we update the time left for the timeout.
                for (int i = 0; i < waitableResults.Length; ++i)
                {
                    // WaitAny don't work with negative numbers
                    if (!waitInfinitely && (millisecondsLeft < 0))
                    {
                        success = false;
                        break;
                    }

                    whs[0] = waitHandles[i];
                    int result = CTPEventWaitHandle.WaitAny(whs, millisecondsLeft, exitContext);
                    if ((result > 0) || (CTPEventWaitHandle.WaitTimeout == result))
                    {
                        success = false;
                        break;
                    }

                    if (!waitInfinitely)
                    {
                        // Update the time left to wait
                        millisecondsLeft = millisecondsTimeout - (int)stopwatch.ElapsedMilliseconds;
                    }
                }
            }
            // Release the wait handles
            ReleaseWaitHandles(waitableResults);

            return(success);
        }
예제 #5
0
 /// <summary>
 /// Wait for the thread pool to be idle
 /// </summary>
 public override bool WaitForIdle(int millisecondsTimeout)
 {
     CThreadPool.ValidateWorkItemsGroupWaitForIdle(this);
     return(CTPEventWaitHandle.WaitOne(_isIdleWaitHandle, millisecondsTimeout, false));
 }