comparison ThreadPool.cs @ 7:4b78cc5f116b

Fixes and improvements (some untested)
author Ivo Smits <Ivo@UCIS.nl>
date Sun, 13 Jan 2013 18:44:17 +0100
parents 3ab940a0c7a0
children 1474f92cf7e7
comparison
equal deleted inserted replaced
6:5ce7a138fdba 7:4b78cc5f116b
1 using System; 1 using System;
2 using System.Collections.Generic;
3 using System.Collections.ObjectModel;
2 using System.Threading; 4 using System.Threading;
3 using System.Collections.Generic;
4 5
5 namespace UCIS { 6 namespace UCIS {
6 public class ThreadPool { 7 public class ThreadPool {
7 private static ThreadPool pManager = null; 8 private static ThreadPool pManager = null;
8 9
47 public Exception Exception; 48 public Exception Exception;
48 public bool ThrowError; 49 public bool ThrowError;
49 } 50 }
50 51
51 private List<ThreadInfo> pThreads = new List<ThreadInfo>(); 52 private List<ThreadInfo> pThreads = new List<ThreadInfo>();
52 private List<ThreadInfo> pBusyThreads = new List<ThreadInfo>(); 53 private int pBusyThreads = 0;
53 private Queue<ThreadInfo> pIdleThreads = new Queue<ThreadInfo>(); 54 private Queue<ThreadInfo> pIdleThreads = new Queue<ThreadInfo>();
54 private int pThreadsMax; 55 private int pThreadsMax;
55 private int pThreadsMinIdle; 56 private int pThreadsMinIdle;
56 private int pThreadsMaxIdle; 57 private int pThreadsMaxIdle;
57 58
58 public event OnExceptionEventHandler OnException; 59 public event OnExceptionEventHandler OnException;
59 public delegate void OnExceptionEventHandler(ThreadPool sender, ExceptionEventArgs e); 60 public delegate void OnExceptionEventHandler(ThreadPool sender, ExceptionEventArgs e);
60 61
61 public System.Collections.ObjectModel.ReadOnlyCollection<ThreadInfo> Threads { 62 public ReadOnlyCollection<ThreadInfo> Threads { get { return pThreads.AsReadOnly(); } }
62 get { 63
63 return new System.Collections.ObjectModel.ReadOnlyCollection<ThreadInfo>(pThreads); 64 public ThreadPool() : this(250, 0, 5) { }
64 }
65 }
66
67 public ThreadPool() : this(250, 1, 5) { }
68 65
69 public ThreadPool(int MaxThreads, int MinIdle, int MaxIdle) { 66 public ThreadPool(int MaxThreads, int MinIdle, int MaxIdle) {
70 int I = 0;
71 if (MaxThreads < 0) { 67 if (MaxThreads < 0) {
72 throw new ArgumentOutOfRangeException("ThreadsMaxIdle", "ThreadsMaxIdle must greater than 0"); 68 throw new ArgumentOutOfRangeException("ThreadsMaxIdle", "ThreadsMaxIdle must greater than 0");
73 } else if (MaxThreads < MaxIdle) { 69 } else if (MaxThreads < MaxIdle) {
74 throw new ArgumentOutOfRangeException("ThreadsMax", "ThreadsMax must be greater than or equal to ThreadsMaxIdle"); 70 throw new ArgumentOutOfRangeException("ThreadsMax", "ThreadsMax must be greater than or equal to ThreadsMaxIdle");
75 } else if (MaxIdle < 0) { 71 } else if (MaxIdle < 0) {
80 throw new ArgumentOutOfRangeException("ThreadsMaxIdle", "ThreadsMaxIdle must be greater than or equal to ThreadsMinIdle"); 76 throw new ArgumentOutOfRangeException("ThreadsMaxIdle", "ThreadsMaxIdle must be greater than or equal to ThreadsMinIdle");
81 } 77 }
82 pThreadsMax = MaxThreads; 78 pThreadsMax = MaxThreads;
83 pThreadsMinIdle = MinIdle; 79 pThreadsMinIdle = MinIdle;
84 pThreadsMaxIdle = MaxIdle; 80 pThreadsMaxIdle = MaxIdle;
85 for (I = 1; I <= pThreadsMinIdle; I++) { 81 for (int I = 1; I <= pThreadsMinIdle; I++) {
86 StartThread(false); 82 StartThread(false);
87 } 83 }
88 } 84 }
89 85
90 public int ThreadsIdle { 86 public int ThreadsIdle { get { return pIdleThreads.Count; } }
91 get { return pIdleThreads.Count; } 87 public int ThreadsBusy { get { return pBusyThreads; } }
92 } 88 public int ThreadsAlive { get { return pThreads.Count; } }
93 public int ThreadsBusy {
94 get { return pBusyThreads.Count; }
95 }
96 public int ThreadsAlive {
97 get { return pThreads.Count; }
98 }
99 public int ThreadsMinIdle { 89 public int ThreadsMinIdle {
100 get { return pThreadsMinIdle; } 90 get { return pThreadsMinIdle; }
101 set { 91 set {
102 if (value > pThreadsMaxIdle) { 92 if (value > pThreadsMaxIdle) {
103 throw new ArgumentOutOfRangeException("ThreadsMinIdle", "ThreadsMinIdle must be smaller than ThreadsMaxIdle"); 93 throw new ArgumentOutOfRangeException("ThreadsMinIdle", "ThreadsMinIdle must be smaller than ThreadsMaxIdle");
117 } 107 }
118 } 108 }
119 public int ThreadsMaxIdle { 109 public int ThreadsMaxIdle {
120 get { return pThreadsMaxIdle; } 110 get { return pThreadsMaxIdle; }
121 set { 111 set {
122 if (pThreadsMinIdle > value) { 112 if (pThreadsMinIdle > value) throw new ArgumentOutOfRangeException("ThreadsMaxIdle", "ThreadsMaxIdle must be greater than or equal to ThreadsMinIdle");
123 throw new ArgumentOutOfRangeException("ThreadsMaxIdle", "ThreadsMaxIdle must be greater than or equal to ThreadsMinIdle"); 113 if (value < 0) throw new ArgumentOutOfRangeException("ThreadsMaxIdle", "ThreadsMaxIdle must greater than or equal to 0");
124 } else if (value < 0) { 114 lock (pIdleThreads) {
125 throw new ArgumentOutOfRangeException("ThreadsMaxIdle", "ThreadsMaxIdle must greater than or equal to 0"); 115 while (value > pIdleThreads.Count) {
126 } else { 116 ThreadInfo T = pIdleThreads.Dequeue();
127 int I = 0; 117 T.Abort = true;
128 int C = 0; 118 T.WaitHandle.Set();
129 ThreadInfo T = default(ThreadInfo); 119 }
130 lock (pIdleThreads) { 120 }
131 C = pIdleThreads.Count; 121 pThreadsMaxIdle = value;
132 if (value < C) {
133 for (I = value; I <= C - 1; I++) {
134 T = pIdleThreads.Dequeue();
135 T.Abort = true;
136 T.WaitHandle.Set();
137 }
138 }
139 }
140 pThreadsMaxIdle = value;
141 }
142 } 122 }
143 } 123 }
144 public int ThreadsMax { 124 public int ThreadsMax {
145 get { return pThreadsMax; } 125 get { return pThreadsMax; }
146 set { 126 set {
147 if (pThreadsMaxIdle > value) { 127 if (pThreadsMaxIdle > value) throw new ArgumentOutOfRangeException("ThreadsMax", "ThreadsMax must be greater than or equal to ThreadsMaxIdle");
148 throw new ArgumentOutOfRangeException("ThreadsMax", "ThreadsMax must be greater than or equal to ThreadsMaxIdle"); 128 if (value <= 0) throw new ArgumentOutOfRangeException("ThreadsMax", "ThreadsMax must greater than 0");
149 } else if (value <= 0) { 129 pThreadsMax = value;
150 throw new ArgumentOutOfRangeException("ThreadsMax", "ThreadsMax must greater than 0");
151 } else {
152 pThreadsMax = value;
153 }
154 } 130 }
155 } 131 }
156 132
157 public WorkItem QueueWorkItem(WaitCallback Callback, object State) { 133 public WorkItem QueueWorkItem(WaitCallback Callback, object State) {
158 WorkItem WorkItem = new WorkItem(); 134 WorkItem WorkItem = new WorkItem() { Callback = Callback, State = State };
159 ThreadInfo Thread = null; 135 ThreadInfo Thread = null;
160 WorkItem.Callback = Callback;
161 WorkItem.State = State;
162 lock (pIdleThreads) { 136 lock (pIdleThreads) {
163 while (pIdleThreads.Count > 0) { 137 while (Thread == null && pIdleThreads.Count > 0) {
164 Thread = pIdleThreads.Dequeue(); 138 Thread = pIdleThreads.Dequeue();
165 if (!Thread.Abort) { 139 if (Thread.Abort) Thread = null;
166 break;
167 } else {
168 Thread = null;
169 }
170 } 140 }
171 } 141 }
172 if (Thread == null) { 142 if (Thread == null) {
173 if (pThreads.Count < pThreadsMax) { 143 if (pThreads.Count >= pThreadsMax) throw new ThreadStateException("Thread limit exceeded");
174 Thread = StartThread(true); 144 Thread = StartThread(true);
175 } else {
176 throw new ThreadStateException("Thread limit exceeded");
177 }
178 } 145 }
179 Thread.LastActive = DateTime.Now; 146 Thread.LastActive = DateTime.Now;
180 WorkItem.Thread = Thread; 147 WorkItem.Thread = Thread;
181 Thread.WorkItem = WorkItem; 148 Thread.WorkItem = WorkItem;
182 Thread.WaitHandle.Set(); 149 Thread.WaitHandle.Set();
233 if (Thread == null) throw new ArgumentNullException("state"); 200 if (Thread == null) throw new ArgumentNullException("state");
234 try { 201 try {
235 while (true) { 202 while (true) {
236 if (Thread.WaitHandle == null) throw new ArgumentNullException("WaitHandle"); 203 if (Thread.WaitHandle == null) throw new ArgumentNullException("WaitHandle");
237 if (!Thread.WaitHandle.WaitOne(1000, false)) { 204 if (!Thread.WaitHandle.WaitOne(1000, false)) {
238 if (pBusyThreads.Count == 0) { 205 if (pBusyThreads <= 0) return;
239 return; 206 continue;
240 } else { 207 }
241 continue;
242 }
243 }
244 if (Thread.Abort) break; 208 if (Thread.Abort) break;
245 209
246 Thread.Busy = true; 210 Thread.Busy = true;
247 lock (pBusyThreads) pBusyThreads.Add(Thread); 211 Interlocked.Increment(ref pBusyThreads);
248 try { 212 try {
249 if (Thread.WorkItem == null) throw new ArgumentNullException("WorkItem"); 213 if (Thread.WorkItem == null) throw new ArgumentNullException("WorkItem");
250 if (Thread.WorkItem.Callback == null) throw new ArgumentNullException("WorkItem.Callback"); 214 if (Thread.WorkItem.Callback == null) throw new ArgumentNullException("WorkItem.Callback");
251 Thread.WorkItem.Callback.Invoke(Thread.WorkItem.State); 215 Thread.WorkItem.Callback.Invoke(Thread.WorkItem.State);
252 } catch (ThreadAbortException ex) { 216 } catch (ThreadAbortException ex) {
260 if (e.ThrowError) { 224 if (e.ThrowError) {
261 Console.WriteLine("Exception in ThreadPool thread: " + e.Exception.ToString()); 225 Console.WriteLine("Exception in ThreadPool thread: " + e.Exception.ToString());
262 throw new Exception("Unhandled exception in work item", e.Exception); 226 throw new Exception("Unhandled exception in work item", e.Exception);
263 } 227 }
264 } finally { 228 } finally {
265 lock (pBusyThreads) pBusyThreads.Remove(Thread); 229 Interlocked.Decrement(ref pBusyThreads);
266 } 230 }
267 Thread.WorkItem.Thread = null; 231 Thread.WorkItem.Thread = null;
268 Thread.WorkItem = null; 232 Thread.WorkItem = null;
269 Thread.Busy = false; 233 Thread.Busy = false;
270 lock (pIdleThreads) { 234 lock (pIdleThreads) {