/// <summary>
        /// Добавить локальную оередь в массив
        /// </summary>
        /// <param name="localQueue">Локальная очередь потока</param>
        public void AddLocalQueue(ThreadPoolLocalQueue localQueue)
        {
            Contract.Requires(localQueue != null);
            Contract.Ensures(Contract.Exists(_localQueues, o => o == localQueue));

            Debug.Assert(!_isDisposed);

            lock (_syncObj)
            {
                var arrayCopy = _localQueues;
                Debug.Assert(arrayCopy != null);

                for (int i = 0; i < arrayCopy.Length; i++)
                {
                    Debug.Assert(Volatile.Read(ref arrayCopy[i]) != localQueue);

                    if (Volatile.Read(ref arrayCopy[i]) == null)
                    {
                        Volatile.Write(ref arrayCopy[i], localQueue);
                        return;
                    }
                }

                int oldLength = arrayCopy.Length;
                Array.Resize(ref arrayCopy, oldLength + 4);

                Volatile.Write(ref arrayCopy[oldLength], localQueue);
                _localQueues = arrayCopy;
            }
        }
        // =====================


        /// <summary>
        /// Попробовать выполнить похищение элемента из соседних локальных очередей
        /// </summary>
        /// <param name="localQueue">Локальная очередь текущего потока</param>
        /// <param name="otherLocalQueues">Разреженный массив локальных очередей других потоков</param>
        /// <param name="item">Выбранный элемент</param>
        /// <returns>Удалось ли сделать выборку</returns>
        private bool TryTakeFromOtherLocalQueues(ThreadPoolLocalQueue localQueue, ThreadPoolLocalQueue[] otherLocalQueues, out ThreadPoolWorkItem item)
        {
            TurboContract.Requires(otherLocalQueues != null, conditionString: "otherLocalQueues != null");
            TurboContract.Ensures(TurboContract.Result <bool>() == false || TurboContract.ValueAtReturn(out item) != null);


            bool result = false;

            item = null;

            try { }
            finally
            {
                int length = otherLocalQueues.Length;
                int index  = Interlocked.Increment(ref _stealIndex) & int.MaxValue;
                for (int i = 0; i < length; i++, index++)
                {
                    var otherQueue = Volatile.Read(ref otherLocalQueues[index % length]);
                    if (otherQueue != null && otherQueue != localQueue && otherQueue.TrySteal(out item))
                    {
                        result = true;
                        break;
                    }
                }
            }

            return(result);
        }
        /// <summary>
        /// Добавить локальную оередь в массив
        /// </summary>
        /// <param name="localQueue">Локальная очередь потока</param>
        public void AddLocalQueue(ThreadPoolLocalQueue localQueue)
        {
            TurboContract.Requires(localQueue != null, conditionString: "localQueue != null");
            TurboContract.Ensures(_localQueues.Contains(localQueue));

            TurboContract.Assert(!_isDisposed, conditionString: "!_isDisposed");

            lock (_syncObj)
            {
                var arrayCopy = _localQueues;
                TurboContract.Assert(arrayCopy != null, conditionString: "arrayCopy != null");

                for (int i = 0; i < arrayCopy.Length; i++)
                {
                    TurboContract.Assert(Volatile.Read(ref arrayCopy[i]) != localQueue, conditionString: "Volatile.Read(ref arrayCopy[i]) != localQueue");

                    if (Volatile.Read(ref arrayCopy[i]) == null)
                    {
                        Volatile.Write(ref arrayCopy[i], localQueue);
                        return;
                    }
                }

                int oldLength = arrayCopy.Length;
                Array.Resize(ref arrayCopy, oldLength + 4);

                Volatile.Write(ref arrayCopy[oldLength], localQueue);
                _localQueues = arrayCopy;
            }
        }
        public ThreadPoolWorkItem Take(ThreadPoolLocalQueue localQueue)
        {
            ThreadPoolWorkItem item = null;
            bool result             = TryTake(localQueue, true, true, out item, -1, new CancellationToken(), true);

            TurboContract.Assert(result, "Something went wrong. Take not return any result.");
            return(item);
        }
        public ThreadPoolWorkItem Take(ThreadPoolLocalQueue localQueue, CancellationToken token)
        {
            ThreadPoolWorkItem item = null;
            bool result             = TryTake(localQueue, true, true, out item, -1, token, true);

            Debug.Assert(result, "Something went wrong. Take not return any result.");
            return(item);
        }
예제 #6
0
        /// <summary>
        /// Конструктор ThreadPoolThreadLocals
        /// </summary>
        /// <param name="globals">Глобальные данные пула</param>
        /// <param name="createLocalQueue">Создавать ли локальную очередь</param>
        public ThreadPoolThreadLocals(ThreadPoolGlobals globals, bool createLocalQueue)
        {
            TurboContract.Requires(globals != null, conditionString: "globals != null");

            Globals = globals;
            if (createLocalQueue)
            {
                LocalQueue = new ThreadPoolLocalQueue();
            }
            _isDisposed = false;
        }
        /// <summary>
        /// Конструктор ThreadPoolThreadLocals
        /// </summary>
        /// <param name="globals">Глобальные данные пула</param>
        /// <param name="createLocalQueue">Создавать ли локальную очередь</param>
        public ThreadPoolThreadLocals(ThreadPoolGlobals globals, bool createLocalQueue)
        {
            Contract.Requires(globals != null);

            Globals = globals;
            if (createLocalQueue)
            {
                LocalQueue = new ThreadPoolLocalQueue();
            }
            _isDisposed = false;
        }
        // ================


        /// <summary>
        /// Переместить все элементы из локальной очереди в общую
        /// </summary>
        /// <param name="localQueue">Локальная очередь</param>
        public void MoveItemsFromLocalQueueToGlobal(ThreadPoolLocalQueue localQueue)
        {
            TurboContract.Requires(localQueue != null, conditionString: "localQueue != null");
            TurboContract.Assert(!_isDisposed, conditionString: "!_isDisposed");

            try { }
            finally
            {
                ThreadPoolWorkItem item = null;
                while (localQueue.TrySteal(out item))
                {
                    _globalQueue.ForceAdd(item);
                }
            }
        }
예제 #9
0
        public bool TryAddItem(ThreadPoolWorkItem item, bool forceGlobal)
        {
            Contract.Requires(item != null);
            Debug.Assert(!_isDisposed);

            ThreadPoolLocalQueue localQueue = null;

            if (!forceGlobal)
            {
                ThreadPoolThreadLocals threadLocal = _perThreadData.Value;
                localQueue = threadLocal != null ? threadLocal.LocalQueue : null;
            }

            return(_queues.TryAdd(item, localQueue, forceGlobal));
        }
예제 #10
0
        public bool TryAddItem(ThreadPoolWorkItem item, bool forceGlobal)
        {
            TurboContract.Requires(item != null, conditionString: "item != null");
            TurboContract.Assert(!_isDisposed, conditionString: "!_isDisposed");

            ThreadPoolLocalQueue localQueue = null;

            if (!forceGlobal)
            {
                ThreadPoolThreadLocals threadLocal = _perThreadData.Value;
                localQueue = threadLocal != null ? threadLocal.LocalQueue : null;
            }

            return(_queues.TryAdd(item, localQueue, forceGlobal));
        }
        // ================


        /// <summary>
        /// Переместить все элементы из локальной очереди в общую
        /// </summary>
        /// <param name="localQueue">Локальная очередь</param>
        public void MoveItemsFromLocalQueueToGlobal(ThreadPoolLocalQueue localQueue)
        {
            Contract.Requires(localQueue != null);
            Debug.Assert(!_isDisposed);

            try { }
            finally
            {
                ThreadPoolWorkItem item = null;
                while (localQueue.TrySteal(out item))
                {
                    _globalQueue.ForceAdd(item);
                }
            }
        }
        /// <summary>
        /// Добавить элемент в очередь
        /// </summary>
        /// <param name="item">Элемент</param>
        /// <param name="localQueue">Локальная очередь (если есть)</param>
        /// <param name="forceGlobal">Обязательное добавление в глобальную очередь</param>
        public void Add(ThreadPoolWorkItem item, ThreadPoolLocalQueue localQueue, bool forceGlobal)
        {
            Contract.Requires(item != null);
            Debug.Assert(!_isDisposed);

            try { }
            finally
            {
                if (forceGlobal || localQueue == null || !localQueue.TryAddLocal(item))
                {
                    bool addToMainRes = _globalQueue.TryAdd(item, -1);
                    Debug.Assert(addToMainRes);
                }
            }
        }
        /// <summary>
        /// Добавить элемент в очередь
        /// </summary>
        /// <param name="item">Элемент</param>
        /// <param name="localQueue">Локальная очередь (если есть)</param>
        /// <param name="forceGlobal">Обязательное добавление в глобальную очередь</param>
        public void Add(ThreadPoolWorkItem item, ThreadPoolLocalQueue localQueue, bool forceGlobal)
        {
            TurboContract.Requires(item != null, conditionString: "item != null");
            TurboContract.Assert(!_isDisposed, conditionString: "!_isDisposed");

            try { }
            finally
            {
                if (forceGlobal || localQueue == null || !localQueue.TryAddLocal(item))
                {
                    bool addToMainRes = _globalQueue.TryAdd(item, -1);
                    TurboContract.Assert(addToMainRes, conditionString: "addToMainRes");
                }
            }
        }
        // ======================


        /// <summary>
        /// Попробовать добавить элемент в очередь
        /// </summary>
        /// <param name="item">Элемент</param>
        /// <param name="localQueue">Локальная очередь потока (если есть)</param>
        /// <param name="forceGlobal">Обязательное добавление в глобальную очередь</param>
        /// <param name="timeout">Таймаут</param>
        /// <param name="token">Токен отмены</param>
        /// <returns>Удалось ли добавить</returns>
        public bool TryAdd(ThreadPoolWorkItem item, ThreadPoolLocalQueue localQueue, bool forceGlobal, int timeout, CancellationToken token)
        {
            TurboContract.Requires(item != null, conditionString: "item != null");
            TurboContract.Assert(!_isDisposed, conditionString: "!_isDisposed");

            if (localQueue != null && !forceGlobal)
            {
                bool added = false;
                try { }
                finally
                {
                    added = localQueue.TryAddLocal(item);
                }
                if (added)
                {
                    return(true);
                }
            }

            return(_globalQueue.TryAdd(item, timeout, token));
        }
        /// <summary>
        /// Удалить локальную очередь из массива
        /// </summary>
        /// <param name="localQueue">Локальная очередь</param>
        public void RemoveLocalQueue(ThreadPoolLocalQueue localQueue)
        {
            Contract.Requires(localQueue != null);
            Contract.Ensures(!Contract.Exists(_localQueues, o => o == localQueue));

            Debug.Assert(!_isDisposed);

            lock (_syncObj)
            {
                var arrayCopy = _localQueues;
                Debug.Assert(arrayCopy != null);

                for (int i = 0; i < arrayCopy.Length; i++)
                {
                    if (object.ReferenceEquals(Volatile.Read(ref arrayCopy[i]), localQueue))
                    {
                        Volatile.Write(ref arrayCopy[i], null);
                        return;
                    }
                }
            }
        }
        /// <summary>
        /// Попробовать добавить элемент в очередь
        /// </summary>
        /// <param name="item">Элемент</param>
        /// <param name="localQueue">Локальная очередь (если есть)</param>
        /// <param name="forceGlobal">Обязательное добавление в глобальную очередь</param>
        /// <returns>Удалось ли добавить</returns>
        public bool TryAdd(ThreadPoolWorkItem item, ThreadPoolLocalQueue localQueue, bool forceGlobal)
        {
            Contract.Requires(item != null);
            Debug.Assert(!_isDisposed);

            bool result = false;

            try { }
            finally
            {
                if (!forceGlobal && localQueue != null && localQueue.TryAddLocal(item))
                {
                    result = true;
                }
                else
                {
                    result = _globalQueue.TryAdd(item, 0);
                }
            }

            return(result);
        }
        /// <summary>
        /// Удалить локальную очередь из массива
        /// </summary>
        /// <param name="localQueue">Локальная очередь</param>
        public void RemoveLocalQueue(ThreadPoolLocalQueue localQueue)
        {
            TurboContract.Requires(localQueue != null, conditionString: "localQueue != null");
            TurboContract.Ensures(!_localQueues.Contains(localQueue));

            TurboContract.Assert(!_isDisposed, conditionString: "!_isDisposed");

            lock (_syncObj)
            {
                var arrayCopy = _localQueues;
                TurboContract.Assert(arrayCopy != null, conditionString: "arrayCopy != null");

                for (int i = 0; i < arrayCopy.Length; i++)
                {
                    if (object.ReferenceEquals(Volatile.Read(ref arrayCopy[i]), localQueue))
                    {
                        Volatile.Write(ref arrayCopy[i], null);
                        return;
                    }
                }
            }
        }
        /// <summary>
        /// Попробовать добавить элемент в очередь
        /// </summary>
        /// <param name="item">Элемент</param>
        /// <param name="localQueue">Локальная очередь (если есть)</param>
        /// <param name="forceGlobal">Обязательное добавление в глобальную очередь</param>
        /// <returns>Удалось ли добавить</returns>
        public bool TryAdd(ThreadPoolWorkItem item, ThreadPoolLocalQueue localQueue, bool forceGlobal)
        {
            TurboContract.Requires(item != null, conditionString: "item != null");
            TurboContract.Assert(!_isDisposed, conditionString: "!_isDisposed");

            bool result = false;

            try { }
            finally
            {
                if (!forceGlobal && localQueue != null && localQueue.TryAddLocal(item))
                {
                    result = true;
                }
                else
                {
                    result = _globalQueue.TryAdd(item, 0);
                }
            }

            return(result);
        }
 public bool TryTake(ThreadPoolLocalQueue localQueue, out ThreadPoolWorkItem item, int timeout, CancellationToken token, bool throwOnCancellation)
 {
     return(TryTake(localQueue, true, true, out item, timeout, token, throwOnCancellation));
 }
        /// <summary>
        /// Попытаться выбрать элемент
        /// </summary>
        /// <param name="localQueue">Локальная очередь (если есть)</param>
        /// <param name="doLocalSearch">Делать ли поиск в локальной очереди</param>
        /// <param name="doWorkSteal">Разрешено ли похищение работы</param>
        /// <param name="item">Выбранный элемент</param>
        /// <param name="timeout">Таймаут</param>
        /// <param name="token">Токен отмены</param>
        /// <param name="throwOnCancellation">Выбрасывать ли исключение при отмене по токену</param>
        /// <returns>Удалось ли выбрать</returns>
        public bool TryTake(ThreadPoolLocalQueue localQueue, bool doLocalSearch, bool doWorkSteal, out ThreadPoolWorkItem item, int timeout, CancellationToken token, bool throwOnCancellation)
        {
            TurboContract.Ensures(TurboContract.Result <bool>() == false || TurboContract.ValueAtReturn(out item) != null);
            TurboContract.Assert(!_isDisposed, conditionString: "!_isDisposed");

            // Пробуем выбрать из локальной очереди
            if (doLocalSearch && localQueue != null)
            {
                bool taken = false;
                try { }
                finally
                {
                    taken = localQueue.TryTakeLocal(out item);
                }
                if (taken)
                {
                    return(true);
                }
            }

            // Если нельзя делать похищение, то сразу забираем из очереди
            if (!doWorkSteal)
            {
                return(_globalQueue.TryTake(out item, timeout, token, throwOnCancellation));
            }

            // Пытаемся выбрать из общей очереди (если не удаётся, то нужно проверить возможность похищения)
            if (_globalQueue.TryTake(out item, 0, new CancellationToken(), false))
            {
                return(true);
            }

            // Пытаемся похитить элемент
            if (TryTakeFromOtherLocalQueues(localQueue, _localQueues, out item))
            {
                return(true);
            }

            if (timeout == 0)
            {
                // Попытки не дали результатов => выходим
                item = null;
                return(false);
            }

            // Если не нужно просыпаться для похищения, то просто выбриаем из общей очереди
            if (_stealAwakePeriod <= 0)
            {
                return(_globalQueue.TryTake(out item, timeout, token, throwOnCancellation));
            }


            if (timeout < 0)
            {
                // Если таймаут не ограничен, то выбираем из основной осереди и периодически пытаемся похитить
                while (true)
                {
                    if (token.IsCancellationRequested)
                    {
                        break;
                    }

                    if (_globalQueue.TryTake(out item, _stealAwakePeriod, token, throwOnCancellation))
                    {
                        return(true);
                    }

                    if (token.IsCancellationRequested)
                    {
                        break;
                    }

                    if (TryTakeFromOtherLocalQueues(localQueue, _localQueues, out item))
                    {
                        return(true);
                    }
                }
            }
            else
            {
                // Делаем замеры таймаута
                uint startTime = GetTimestamp();
                int  restTime  = timeout;

                while (restTime > 0)
                {
                    if (token.IsCancellationRequested)
                    {
                        break;
                    }

                    if (_globalQueue.TryTake(out item, Math.Min(_stealAwakePeriod, restTime), token, throwOnCancellation))
                    {
                        return(true);
                    }

                    if (token.IsCancellationRequested)
                    {
                        break;
                    }

                    if (TryTakeFromOtherLocalQueues(localQueue, _localQueues, out item))
                    {
                        return(true);
                    }

                    restTime = UpdateTimeout(startTime, timeout);
                }
            }

            if (token.IsCancellationRequested && throwOnCancellation)
            {
                throw new OperationCanceledException(token);
            }

            item = null;
            return(false);
        }
 public void Add(ThreadPoolWorkItem item, ThreadPoolLocalQueue localQueue)
 {
     this.Add(item, localQueue, false);
 }
 public bool TryAdd(ThreadPoolWorkItem item, ThreadPoolLocalQueue localQueue)
 {
     return(this.TryAdd(item, localQueue, false));
 }