/// <summary>
        /// Raises the AfterWorkItem event
        /// </summary>
        void OnAfterWorkItem(ThreadPoolWorkItem workItem)
        {
            AfterWorkItemHandler delegateToFire;

            lock (eventLock)
            {
                delegateToFire = afterWorkItem;
            }
            if (delegateToFire != null)
            {
                delegateToFire(this, workItem);
            }
        }
        /// <summary>
        /// Adds a work item to the queue and potentially start a new thread.
        /// A thread is started if there are no idle threads or if there is already
        /// something on the queue - but in each case, only if the total number of
        /// threads is less than the maximum.
        /// </summary>
        /// <param name="workItem">The actual work item to add to the queue.</param>
        public void AddWorkItem(ThreadPoolWorkItem workItem)
        {
            if (workItem == null)
            {
                throw new ArgumentNullException("workItem");
            }
            bool startNewThread;

            lock (stateLock)
            {
                lock (queueLock)
                {
                    if (queue.Count == 0)
                    {
                        queue.Enqueue(workItem);
                    }
                    else
                    {
                        // Work out where in the queue the item should go

                        // Common case: it belongs at the end
                        if (((ThreadPoolWorkItem)queue[queue.Count - 1]).Priority >= workItem.Priority)
                        {
                            queue.Enqueue(workItem);
                        }
                        else
                        {
                            // This will find the complement of the correct position, due to the
                            // "interesting" nature of PriorityComparer.
                            int position = queue.BinarySearch(workItem, PriorityComparer.Instance);
                            queue.Enqueue(workItem, ~position);
                        }
                    }
                    startNewThread = (WorkingThreads + queue.Count > TotalThreads) &&
                                     (TotalThreads < MaxThreads);
                    // Always pulse the queueLock, whether there's something waiting or not.
                    // This is easier than trying to work out for sure whether or not it's
                    // worth pulsing, and errs on the side of caution.
                    Monitor.Pulse(queueLock);
                }
            }
            if (startNewThread)
            {
                StartWorkerThread();
            }
        }
 /// <summary>
 /// Cancels the first work item with the specified ID, if there is one.
 /// Note that items which have been taken off the queue and are running
 /// or about to be started cannot be cancelled.
 /// </summary>
 /// <param name="id">The ID of the work item to cancel</param>
 public bool CancelWorkItem(object id)
 {
     if (id == null)
     {
         throw new ArgumentNullException("id");
     }
     lock (queueLock)
     {
         for (int i = 0; i < queue.Count; i++)
         {
             ThreadPoolWorkItem item    = (ThreadPoolWorkItem)queue[i];
             object             otherID = item.ID;
             if (otherID != null && id.Equals(otherID))
             {
                 queue.RemoveAt(i);
                 return(true);
             }
         }
     }
     return(false);
 }
        /// <summary>
        /// Main worker thread loop. This picks jobs off the queue and executes
        /// them, until it's time to die.
        /// </summary>
        void WorkerThreadLoop()
        {
            // Big try/finally block just to decrement the number of threads whatever happens.
            try
            {
                DateTime lastJob = DateTime.UtcNow;
                while (true)
                {
                    lock (stateLock)
                    {
                        if (TotalThreads > MaxThreads)
                        {
                            return;
                        }
                    }
                    int waitPeriod = CalculateWaitPeriod(lastJob);

                    ThreadPoolWorkItem job = GetNextWorkItem(waitPeriod);

                    // No job? Check whether or not we should die
                    if (job == null)
                    {
                        if (CheckIfThreadShouldQuit(lastJob))
                        {
                            return;
                        }
                    }
                    else
                    {
                        ExecuteWorkItem(job);
                        lastJob = DateTime.UtcNow;
                    }
                }
            }
            finally
            {
                OnWorkerThreadExit();
            }
        }
        /// <summary>
        /// Raises the BeforeWorkItem event
        /// </summary>
        /// <param name="workItem">The work item which is about to execute</param>
        /// <param name="cancel">Whether or not the work item was cancelled by an event handler</param>
        void OnBeforeWorkItem(ThreadPoolWorkItem workItem, out bool cancel)
        {
            cancel = false;
            BeforeWorkItemHandler delegateToFire;

            lock (eventLock)
            {
                delegateToFire = beforeWorkItem;
            }
            if (delegateToFire != null)
            {
                Delegate[] delegates = delegateToFire.GetInvocationList();
                foreach (BeforeWorkItemHandler d in delegates)
                {
                    d(this, workItem, ref cancel);
                    if (cancel)
                    {
                        return;
                    }
                }
            }
        }
        /// <summary>
        /// Raises the WorkerException event.
        /// TODO: Write to the event log if no exception handlers are attached?
        /// </summary>
        void OnException(ThreadPoolWorkItem workItem, Exception e)
        {
            ThreadPoolExceptionHandler eh;

            lock (eventLock)
            {
                eh = exceptionHandler;
            }
            if (eh != null)
            {
                Delegate[] delegates = eh.GetInvocationList();
                bool       handled   = false;
                foreach (ThreadPoolExceptionHandler d in delegates)
                {
                    d(this, workItem, e, ref handled);
                    if (handled)
                    {
                        return;
                    }
                }
            }
        }
 /// <summary>
 /// Executes the given work item, firing the BeforeWorkItem and AfterWorkItem events,
 /// and incrementing and decrementing the number of working threads.
 /// </summary>
 /// <param name="job">The work item to execute</param>
 void ExecuteWorkItem(ThreadPoolWorkItem job)
 {
     lock (stateLock)
     {
         workingThreads++;
         Thread.CurrentThread.Priority     = workerThreadPriority;
         Thread.CurrentThread.IsBackground = workerThreadsAreBackground;
     }
     try
     {
         bool cancel;
         OnBeforeWorkItem(job, out cancel);
         if (cancel)
         {
             return;
         }
         try
         {
             job.Invoke();
         }
         catch (Exception e)
         {
             OnException(job, e);
             return;
         }
         OnAfterWorkItem(job);
     }
     finally
     {
         lock (stateLock)
         {
             Thread.CurrentThread.Priority     = workerThreadPriority;
             Thread.CurrentThread.IsBackground = workerThreadsAreBackground;
             workingThreads--;
         }
     }
 }