/// <summary> /// Queues a user work item to the thread pool. /// </summary> /// <param name="callback">A WaitCallback representing the method to execute.</param> /// <param name="state">An object containing data to be used by the method.</param> /// <param name="longDuration">Indicates whether the item depends on other working threads or can take a long period to finish.</param> public static void QueueUserWorkItem(WaitCallback callback, object state, bool longDuration) { GenuineThreadPoolStrategy theStrategy = GenuineThreadPool.GenuineThreadPoolStrategy; if (callback == null) { throw new NullReferenceException("callback"); } CustomThreadInfo customThreadInfo = null; lock (_threadsLock) { BinaryLogWriter binaryLogWriter = GenuineLoggingServices.BinaryLogWriter; if (binaryLogWriter != null && binaryLogWriter[LogCategory.StatisticCounters] > 0 && (Interlocked.Increment(ref _QueueUserWorkItem_OperationNumber) % GenuineThreadPool.ThreadStatisticFrequency) == 0) { binaryLogWriter.WriteEvent(LogCategory.StatisticCounters, "GenuineThreadPool.QueueUserWorkItem", LogMessageType.ThreadPoolUsage, null, null, null, null, GenuineUtility.CurrentThreadId, Thread.CurrentThread.Name, null, null, -1, _QueueUserWorkItem_OperationNumber, GenuineThreadPool._threads.Count, 0, null, null, null, null, "GenuineThreadPool has received a request #{0} (object \"{1}\" entry \"{2}\"). The current number of working threads: {3}. ThreadPoolAvailableThreads: {4}. MaximumThreads: {5}. CloseAfterInactivity: {6}. UnsafeQueuing: {7}. GenuineThreadPoolStrategy: {8}.", _QueueUserWorkItem_OperationNumber, callback.Method.ReflectedType.ToString(), callback.Method.ToString(), GenuineThreadPool._threads.Count, GenuineThreadPool.ThreadPoolAvailableThreads, GenuineThreadPool.MaximumThreads, GenuineThreadPool.CloseAfterInactivity.TotalMilliseconds, GenuineThreadPool.UnsafeQueuing, Enum.Format(typeof(GenuineThreadPoolStrategy), GenuineThreadPool.GenuineThreadPoolStrategy, "g") ); } if (!(theStrategy == GenuineThreadPoolStrategy.AlwaysThreads || (theStrategy == GenuineThreadPoolStrategy.OnlyLongDuration && longDuration))) { // try to use native ThreadPool if it's possible int workerThreads = 0; int completionPortThreads = 0; if (theStrategy == GenuineThreadPoolStrategy.SwitchAfterExhaustion) { ThreadPool.GetAvailableThreads(out workerThreads, out completionPortThreads); } if (theStrategy == GenuineThreadPoolStrategy.AlwaysNative || theStrategy == GenuineThreadPoolStrategy.OnlyLongDuration || (Math.Min(workerThreads, completionPortThreads) >= GenuineThreadPool.ThreadPoolAvailableThreads && theStrategy == GenuineThreadPoolStrategy.SwitchAfterExhaustion)) { if (GenuineThreadPool.UnsafeQueuing) { ThreadPool.UnsafeQueueUserWorkItem(callback, state); } else { ThreadPool.QueueUserWorkItem(callback, state); } return; } } // look for an available worker thread for (int i = 0; i < _threads.Count;) { // get the next thread customThreadInfo = (CustomThreadInfo)_threads[i]; // check if it's alive if (!customThreadInfo.IsAlive) { _threads.RemoveAt(i); customThreadInfo = null; continue; } if (customThreadInfo.IsIdle) { break; } customThreadInfo = null; i++; } // if the limit is exceeded if (customThreadInfo == null && _threads.Count >= GenuineThreadPool.MaximumThreads) { if (GenuineThreadPool.AllowRequestQueuing) { _requestsQueued.Enqueue(new GenuineThreadPoolWorkItem(callback, state)); return; } else { throw GenuineExceptions.Get_Processing_ThreadPoolLimitExceeded(); } } // create a new one, if it's necessary if (customThreadInfo == null) { customThreadInfo = new CustomThreadInfo(_threadsLock); _threads.Add(customThreadInfo); } // give out the work customThreadInfo.WorkCallback = callback; customThreadInfo.CallbackState = state; customThreadInfo.IsIdle = false; customThreadInfo.ManualResetEvent.Set(); } }