예제 #1
0
        /// <summary>
        /// Raises the WorkerException event.
        /// TODO: Write to the event log if no exception handlers are attached?
        /// </summary>
        private void OnException(ThreadPoolWorkItem workItem, Exception e)
        {
            ThreadPoolExceptionHandler eh;

            lock (_eventLock)
            {
                eh = WorkerException;
            }

            if (eh == null)
            {
                return;
            }

            Delegate[] delegates = eh.GetInvocationList();
            bool       handled   = false;

            foreach (ThreadPoolExceptionHandler d in delegates.OfType <ThreadPoolExceptionHandler>())
            {
                d(this, workItem, e, ref handled);
                if (handled)
                {
                    return;
                }
            }
        }
예제 #2
0
        /// <summary>
        /// Raises the AfterWorkItem event
        /// </summary>
        private void OnAfterWorkItem(ThreadPoolWorkItem workItem)
        {
            AfterWorkItemHandler delegateToFire;

            lock (_eventLock)
            {
                delegateToFire = AfterWorkItem;
            }

            delegateToFire?.Invoke(this, workItem);
        }
예제 #3
0
        /// <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([NotNull] ThreadPoolWorkItem workItem)
        {
            if (workItem == null)
            {
                throw new ArgumentNullException(nameof(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 (_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();
            }
        }
예제 #4
0
        /// <summary>
        /// Main worker thread loop. This picks jobs off the queue and executes
        /// them, until it's time to die.
        /// </summary>
        private 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();
            }
        }
예제 #5
0
        /// <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>
        private void ExecuteWorkItem([NotNull] ThreadPoolWorkItem job)
        {
            lock (_stateLock)
            {
                Interlocked.Increment(ref _workingThreads);
                Thread.CurrentThread.Priority     = _workerThreadPriority;
                Thread.CurrentThread.IsBackground = _workerThreadsAreBackground;
            }

            try
            {
                OnBeforeWorkItem(job, out bool 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;
                    Interlocked.Decrement(ref _workingThreads);
                }
            }
        }
예제 #6
0
        /// <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([NotNull] object id)
        {
            if (id == null)
            {
                throw new ArgumentNullException(nameof(id));
            }

            lock (_queueLock)
            {
                for (int i = 0; i < _queue.Count; i++)
                {
                    ThreadPoolWorkItem item    = _queue[i];
                    object             otherID = item.ID;

                    if (otherID != null && id.Equals(otherID))
                    {
                        _queue.RemoveAt(i);
                        return(true);
                    }
                }
            }
            return(false);
        }
예제 #7
0
        /// <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>
        private 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.OfType <BeforeWorkItemHandler>())
                {
                    d(this, workItem, ref cancel);
                    if (cancel)
                    {
                        return;
                    }
                }
            }
        }