private void OnThreadPoolThreadExit(ThreadPoolThread exitedThread) { lock (_sync) { if (_idleThreads.Count <= _minThreadCount) { return; } Stack <ThreadPoolThread> threads = new Stack <ThreadPoolThread>(); while (_idleThreads.Count != 0) { ThreadPoolThread thread = _idleThreads.Pop(); if (thread == exitedThread) { if (!_semaphore.WaitOne(0)) { throw new Exception("Semaphore count is invalid."); } break; } threads.Push(thread); } while (threads.Count != 0) { _idleThreads.Push(threads.Pop()); } } }
/// <summary> /// This puts a work request on the queue to be executed. The logic then immediatly tries to assign a thread the work. /// </summary> /// <param name="work"></param> public void AssignThread(Action work) { ThreadPoolThread thread = null; Action currentWork = null; lock (_lock) { if (IsDisposed) { return; } _workQueue.Enqueue(work); Interlocked.Increment(ref _workQueueSize); if (_availableThreads.Count == 0) { return; } // okay have thread and have work thread = _availableThreads.Dequeue(); Interlocked.Increment(ref _threadsAssigned); currentWork = _workQueue.Dequeue(); // this seems strange to deque right after an enqueue but there could be work waiting on the work queue Interlocked.Decrement(ref _workQueueSize); } // we do it here -- the thread and must not be null and should not according to the above logic thread.AssignWork(currentWork); }
/// <summary> /// Creates a ThreadPoolThread instance. /// </summary> /// <param name="id">The id for the thread.</param> /// <returns>The created thread</returns> private ThreadPoolThread BuildThread(int id) { ThreadPoolThread thread = new ThreadPoolThread(_poolName, id + 1, ThreadStarting); thread.OnFinished += WorkFinished; return(thread); }
/// <summary> Puts the thread 't' in the idle list. The thread 't' should be in fact /// idle and ready to accept a new target when it joins the idle list. /// /// <P> An idle thread that is already in the list should never add itself /// to the list before it is removed. For efficiency reasons there is no /// check to see if the thread is already in the list of idle threads. /// /// <P> If the idle list was empty 'notify()' will be called on the 'idle' /// array, to wake up a thread that might be waiting (within the /// 'getIdle()' method) on an idle thread to become available. /// /// </summary> /// <param name="t">The thread to put in the idle list. /// /// </param> private void putInIdleList(ThreadPoolThread t) { // NOTE: if already in idle => catastrophe! (should be OK since // // this is private method) // Lock the idle array to avoid races with 'getIdle()' lock (idle) { idle[nidle] = t; nidle++; // If idle array was empty wakeup any waiting threads. if (nidle == 1) { System.Threading.Monitor.Pulse(idle); } } }
/// <summary> /// Fires the OnNewThreadPoolThread event. /// </summary> /// <param name="thread"></param> private void ThreadStarting(ThreadPoolThread thread) { if (null != OnNewThreadPoolThread) { try { OnNewThreadPoolThread(this, new NewThreadPoolThreadArgs() { name = thread.Name, thread = thread.Thread }); } catch (Exception) { throw; } } }
/// <summary> Creates a new thread pool of the given size, thread priority and pool /// name. /// /// <P>If the Java system property of the name defined by /// 'CONCURRENCY_PROP_NAME' is set, then an attempt will be made to load /// the library that supports concurrency setting (see /// 'NativeServices'). If that succeds the concurrency level will be set to /// the specified value. Otherwise a warning is printed. /// /// </summary> /// <param name="size">The size of the pool (number of threads to create in the /// pool). /// /// </param> /// <param name="priority">The priority to give to the threads in the pool. If /// less than 'Thread.MIN_PRIORITY' it will be the same as the priority of /// the calling thread. /// /// </param> /// <param name="name">The name of the pool. If null a default generic name is /// chosen. /// /// </param> /// <seealso cref="NativeServices"> /// /// </seealso> /// <seealso cref="CONCURRENCY_PROP_NAME"> /// /// </seealso> public ThreadPool(int size, int priority, System.String name) { int i; ThreadPoolThread t; //System.String prop; //int clevel; // Initialize variables checking for special cases if (size <= 0) { throw new System.ArgumentException("Pool must be of positive size"); } if (priority < (int)System.Threading.ThreadPriority.Lowest) { poolPriority = (System.Int32)SupportClass.ThreadClass.Current().Priority; } else { poolPriority = (priority < (int)System.Threading.ThreadPriority.Highest)?priority:(int)System.Threading.ThreadPriority.Highest; } if (name == null) { poolName = "Anonymous ThreadPool"; } else { poolName = name; } // Allocate internal variables idle = new ThreadPoolThread[size]; nidle = 0; // Create and start the threads for (i = 0; i < size; i++) { t = new ThreadPoolThread(this, i, poolName + "-" + i); t.Start(); } }
/// <summary> /// Kills the assigned work off that is in a thread. /// </summary> /// <param name="work"></param> public void KillThread(Action work) { ThreadPoolThread t = null; lock (_lock) { int cnt = _allThreads.Length; for (int i = 0; i < cnt; i++) { t = _allThreads[i]; if (t.Work == work) { goto kill_it; } } return; } kill_it: t.KillWork(); }
/// <summary> /// This is called by the ThreadPoolThread when it's finished processing the unit of work it was given. /// </summary> /// <param name="thread">The thread that finished</param> private void WorkFinished(ThreadPoolThread thread) { if (IsDisposed) { return; } Action currentWork = null; lock (_lock) { if (_workQueue.Count > 0) { currentWork = _workQueue.Dequeue(); Interlocked.Decrement(ref _workQueueSize); } else { _availableThreads.Enqueue(thread); Interlocked.Decrement(ref _threadsAssigned); } } if (null != currentWork) { thread.AssignWork(currentWork); } if (null != OnThreadFinished) { try { OnThreadFinished(this, new EventArgs()); } catch (Exception) { } } }
public void QueueWorkItem(Action action) { _schedulerThread.QueueWorkItem(() => { ThreadPoolThread thread; if (_semaphore.WaitOne(_threadCreationDelay)) { lock (_sync) { thread = _idleThreads.Pop(); } } else { thread = new ThreadPoolThread(this); } thread.QueueWorkItem(action); thread.QueueWorkItem(() => { lock (_sync) { _idleThreads.Push(thread); _semaphore.Release(); } }); }); }
/// <summary> Puts the thread 't' in the idle list. The thread 't' should be in fact /// idle and ready to accept a new target when it joins the idle list. /// /// <P> An idle thread that is already in the list should never add itself /// to the list before it is removed. For efficiency reasons there is no /// check to see if the thread is already in the list of idle threads. /// /// <P> If the idle list was empty 'notify()' will be called on the 'idle' /// array, to wake up a thread that might be waiting (within the /// 'getIdle()' method) on an idle thread to become available. /// /// </summary> /// <param name="t">The thread to put in the idle list. /// /// </param> private void putInIdleList(ThreadPoolThread t) { // NOTE: if already in idle => catastrophe! (should be OK since // // this is private method) // Lock the idle array to avoid races with 'getIdle()' lock (idle) { idle[nidle] = t; nidle++; // If idle array was empty wakeup any waiting threads. if (nidle == 1) System.Threading.Monitor.Pulse(idle); } }
/// <summary> Creates a new thread pool of the given size, thread priority and pool /// name. /// /// <P>If the Java system property of the name defined by /// 'CONCURRENCY_PROP_NAME' is set, then an attempt will be made to load /// the library that supports concurrency setting (see /// 'NativeServices'). If that succeds the concurrency level will be set to /// the specified value. Otherwise a warning is printed. /// /// </summary> /// <param name="size">The size of the pool (number of threads to create in the /// pool). /// /// </param> /// <param name="priority">The priority to give to the threads in the pool. If /// less than 'Thread.MIN_PRIORITY' it will be the same as the priority of /// the calling thread. /// /// </param> /// <param name="name">The name of the pool. If null a default generic name is /// chosen. /// /// </param> /// <seealso cref="NativeServices"> /// /// </seealso> /// <seealso cref="CONCURRENCY_PROP_NAME"> /// /// </seealso> public ThreadPool(int size, int priority, System.String name) { int i; ThreadPoolThread t; //System.String prop; //int clevel; // Initialize variables checking for special cases if (size <= 0) { throw new System.ArgumentException("Pool must be of positive size"); } if (priority < (int) System.Threading.ThreadPriority.Lowest) { poolPriority = (System.Int32) SupportClass.ThreadClass.Current().Priority; } else { poolPriority = (priority < (int) System.Threading.ThreadPriority.Highest)?priority:(int) System.Threading.ThreadPriority.Highest; } if (name == null) { poolName = "Anonymous ThreadPool"; } else { poolName = name; } // Allocate internal variables idle = new ThreadPoolThread[size]; nidle = 0; // Create and start the threads for (i = 0; i < size; i++) { t = new ThreadPoolThread(this, i, poolName + "-" + i); t.Start(); } }