/// <summary> /// Creates new threadpool with given settings and cancel token values /// </summary> /// <param name="settings">thread pool runtime settings</param> /// <param name="cancelToken">cancel token to indicate or send stop event to the pool</param> public CustomThreadPool3(ThreadPoolSettings settings, CancellationToken cancelToken) : base(settings, cancelToken) { _settings = settings; _linkedCts = CancellationTokenSource.CreateLinkedTokenSource(cancelToken); this._poolStopToken = _linkedCts.Token; _tokenRegister = _poolStopToken.Register(OnPoolCancelRequested); //start minimum required threads immediately _mThreads = new Thread[_settings.MaxThreads]; _mThreadLocalQueues = new ThreadLocalStealQueue<ThreadPoolWorkItem>[_settings.MaxThreads]; for (int i = 0; i < _settings.MinThreads; i++) { StartNewThread(true); } EtwLogger.Log.PoolStarted(Name, _settings.MinThreads, _settings.MaxThreads); }
private void WorkItemDispatchLoop(object threadData) { var startinfo = (WorkerThreadStartParams)threadData; // Register a new WSQ. var wsq = new ThreadLocalStealQueue<ThreadPoolWorkItem>(); wsq.Name = startinfo.ThreadName; _mWsq = wsq; // Store in TLS. AddNewWorkQueue(wsq); DateTime lastItemProcesTime = DateTime.UtcNow; try { while (true) { if (ShouldThreadExit(lastItemProcesTime, startinfo.IsPermenant)) { return; } var wi = default(ThreadPoolWorkItem); // Search order: (1) local queue, (2) global Queue, (3) steal from another thread. if (!wsq.LocalPop(ref wi)) { if (ShouldThreadExit(lastItemProcesTime, startinfo.IsPermenant)) { return; } lock (_mQueue) { // If shutdown was requested, exit the thread. if (_poolStopToken.IsCancellationRequested) return; // (2) try the global queue. if (_mQueue.Count != 0) { // We found a work item! Grab it … wi = _mQueue.Dequeue(); } } if (wi == null) { lock (_mThreadLocalQueues) { // (3) try to steal from neighbour thread. ThreadLocalStealQueue<ThreadPoolWorkItem>[] wsQueues = _mThreadLocalQueues; int i; for (i = 0; i < wsQueues.Length; i++) { if (wsQueues[i] != null) { if (wsQueues[i] != wsq && wsQueues[i].TrySteal(ref wi)) break; } } } } } try { //we got a work item, now try to invoke it. if (wi != null) { wi.Execute(); lastItemProcesTime = DateTime.UtcNow; } } catch (Exception ex) { EtwLogger.Log.WorkItemFailure(ex.ToString()); if (UserWorkItemException != null) { UserWorkItemException(this, new WorkItemEventArgs { Exception = ex, UserData = wi.UserData, }); } } } } finally { OnWorkerThreadExit(startinfo.ThreadName); } }
private void AddNewWorkQueue(ThreadLocalStealQueue<ThreadPoolWorkItem> wsq) { lock (_mThreadLocalQueues) { for (int i = 0; i < _mThreadLocalQueues.Length; i++) { if (_mThreadLocalQueues[i] == null) { _mThreadLocalQueues[i] = wsq; break; } else if (_mThreadLocalQueues[i].Name == wsq.Name) { _mThreadLocalQueues[i] = wsq; break; } else if (i == _mThreadLocalQueues.Length - 1) { //expand the array now. var queues = new ThreadLocalStealQueue<ThreadPoolWorkItem>[_mThreadLocalQueues.Length * 2]; Array.Copy(_mThreadLocalQueues, queues, i + 1); queues[i + 1] = wsq; _mThreadLocalQueues = queues; } } } }