2 // System.Threading.ThreadPool
6 // Dick Porter (dick@ximian.com)
8 // (C) Ximian, Inc. http://www.ximian.com
9 // (C) Patrik Torstensson
12 using System.Collections;
14 namespace System.Threading {
15 /// <summary> (Patrik T notes)
16 /// This threadpool is focused on saving resources not giving max performance.
18 /// Note, this class is not perfect but it works. ;-) Should also replace
19 /// the queue with an internal one (performance)
21 /// This class should also use a specialized queue to increase performance..
24 public sealed class ThreadPool {
25 internal struct ThreadPoolWorkItem {
26 public WaitCallback _CallBack;
27 public object _Context;
30 private int _ThreadTimeout;
32 private long _MaxThreads;
33 private long _CurrentThreads;
34 private long _ThreadsInUse;
35 private long _RequestInQueue;
36 private long _ThreadCreateTriggerRequests;
38 private Thread _MonitorThread;
39 private Queue _RequestQueue;
41 private ArrayList _Threads;
42 private ManualResetEvent _DataInQueue;
44 static ThreadPool _Threadpool;
47 _Threadpool = new ThreadPool();
50 private ThreadPool() {
51 // 30 sec timeout default
52 _ThreadTimeout = 30 * 1000;
54 // Used to signal that there is data in the queue
55 _DataInQueue = new ManualResetEvent(false);
57 _Threads = ArrayList.Synchronized(new ArrayList());
60 _RequestQueue = Queue.Synchronized(new Queue(128));
62 // TODO: This should be 2 x number of CPU:s in the box
67 _ThreadCreateTriggerRequests = 5;
69 // TODO: This temp starts one thread, remove this..
72 // Keeps track of requests in the queue and increases the number of threads if needed
74 // PT: Disabled - causes problems during shutdown
75 //_MonitorThread = new Thread(new ThreadStart(MonitorThread));
76 //_MonitorThread.Start();
79 internal void RemoveThread() {
80 Interlocked.Decrement(ref _CurrentThreads);
81 _Threads.Remove(Thread.CurrentThread);
84 internal void CheckIfStartThread() {
85 bool bCreateThread = false;
87 if (_CurrentThreads == 0) {
91 if (( _MaxThreads == -1 || _CurrentThreads < _MaxThreads) &&
93 _RequestInQueue >= _ThreadCreateTriggerRequests) {
98 Interlocked.Increment(ref _CurrentThreads);
100 Thread Start = new Thread(new ThreadStart(WorkerThread));
101 Start.IsThreadPoolThreadInternal = true;
102 Start.IsBackground = true;
109 internal void AddItem(ref ThreadPoolWorkItem Item) {
110 _RequestQueue.Enqueue(Item);
111 if (Interlocked.Increment(ref _RequestInQueue) == 1) {
116 // Work Thread main function
117 internal void WorkerThread() {
118 bool bWaitForData = true;
122 if (!_DataInQueue.WaitOne(_ThreadTimeout, false)) {
123 // Keep one thread running
124 if (_CurrentThreads > 1) {
133 Interlocked.Increment(ref _ThreadsInUse);
135 // TODO: Remove when we know how to stop the watch thread
136 CheckIfStartThread();
139 ThreadPoolWorkItem oItem = (ThreadPoolWorkItem) _RequestQueue.Dequeue();
141 if (Interlocked.Decrement(ref _RequestInQueue) == 0) {
142 _DataInQueue.Reset();
145 oItem._CallBack(oItem._Context);
147 catch (InvalidOperationException) {
151 catch (ThreadAbortException) {
152 // We will leave here.. (thread abort can't be handled)
156 Interlocked.Decrement(ref _ThreadsInUse);
161 /* This is currently not in use
163 internal void MonitorThread() {
165 if (_DataInQueue.WaitOne ()) {
166 CheckIfStartThread();
174 internal bool QueueUserWorkItemInternal(WaitCallback callback) {
175 return QueueUserWorkItem(callback, null);
178 internal bool QueueUserWorkItemInternal(WaitCallback callback, object context) {
179 ThreadPoolWorkItem Item = new ThreadPoolWorkItem();
181 Item._CallBack = callback;
182 Item._Context = context;
186 // LAMESPEC: Return value? should use exception here if anything goes wrong
190 public static bool BindHandle(IntPtr osHandle) {
191 throw new NotSupportedException("This is a win32 specific method, not supported Mono");
194 public static bool QueueUserWorkItem(WaitCallback callback) {
195 return _Threadpool.QueueUserWorkItemInternal(callback);
198 public static bool QueueUserWorkItem(WaitCallback callback, object state) {
199 return _Threadpool.QueueUserWorkItemInternal(callback, state);
202 public static bool UnsafeQueueUserWorkItem(WaitCallback callback, object state) {
203 return _Threadpool.QueueUserWorkItemInternal(callback, state);
206 static TimeSpan GetTSFromMS (long ms)
209 throw new ArgumentOutOfRangeException ("millisecondsTimeOutInterval", "timeout < -1");
211 return new TimeSpan (0, 0, 0, 0, (int) ms);
214 public static RegisteredWaitHandle RegisterWaitForSingleObject (WaitHandle waitObject,
215 WaitOrTimerCallback callback,
217 int millisecondsTimeOutInterval,
218 bool executeOnlyOnce)
220 TimeSpan ts = GetTSFromMS ((long) millisecondsTimeOutInterval);
221 return RegisterWaitForSingleObject (waitObject, callback, state, ts, executeOnlyOnce);
224 public static RegisteredWaitHandle RegisterWaitForSingleObject (WaitHandle waitObject,
225 WaitOrTimerCallback callback,
227 long millisecondsTimeOutInterval,
228 bool executeOnlyOnce)
230 TimeSpan ts = GetTSFromMS (millisecondsTimeOutInterval);
231 return RegisterWaitForSingleObject (waitObject, callback, state, ts, executeOnlyOnce);
234 public static RegisteredWaitHandle RegisterWaitForSingleObject (WaitHandle waitObject,
235 WaitOrTimerCallback callback,
238 bool executeOnlyOnce)
240 long ms = (long) timeout.TotalMilliseconds;
242 throw new ArgumentOutOfRangeException ("timeout", "timeout < -1");
244 if (ms > Int32.MaxValue)
245 throw new NotSupportedException ("Timeout is too big. Maximum is Int32.MaxValue");
247 RegisteredWaitHandle waiter = new RegisteredWaitHandle (waitObject, callback, state, timeout, executeOnlyOnce);
248 _Threadpool.QueueUserWorkItemInternal (new WaitCallback (waiter.Wait), null);
252 [CLSCompliant(false)]
253 public static RegisteredWaitHandle RegisterWaitForSingleObject (WaitHandle waitObject,
254 WaitOrTimerCallback callback,
256 uint millisecondsTimeOutInterval,
257 bool executeOnlyOnce)
259 TimeSpan ts = GetTSFromMS ((long) millisecondsTimeOutInterval);
260 return RegisterWaitForSingleObject (waitObject, callback, state, ts, executeOnlyOnce);
264 public static RegisteredWaitHandle UnsafeRegisterWaitForSingleObject(WaitHandle waitObject, WaitOrTimerCallback callback, object state, int millisecondsTimeOutInterval, bool executeOnlyOnce) {
265 throw new NotImplementedException();
269 public static RegisteredWaitHandle UnsafeRegisterWaitForSingleObject(WaitHandle waitObject, WaitOrTimerCallback callback, object state, long millisecondsTimeOutInterval, bool executeOnlyOnce) {
270 throw new NotImplementedException();
274 public static RegisteredWaitHandle UnsafeRegisterWaitForSingleObject(WaitHandle waitObject, WaitOrTimerCallback callback, object state, TimeSpan timeout, bool executeOnlyOnce) {
275 throw new NotImplementedException();
278 [CLSCompliant(false)][MonoTODO]
279 public static RegisteredWaitHandle UnsafeRegisterWaitForSingleObject(WaitHandle waitObject, WaitOrTimerCallback callback, object state, uint millisecondsTimeOutInterval, bool executeOnlyOnce) {
280 throw new NotImplementedException();