C # фиксированный размер ConcurrentQueue получить элемент по индексу - PullRequest
0 голосов
/ 19 января 2019

Я нашел старый код, который реализует потокобезопасную очередь. и я попытался создать новую реализацию, используя ConcurrentQueue

Старый код

public class BoundedQueue<T> where T : class
    {
        private readonly Queue<T> _fixedSizeBuffer;
        private object _bufferLock;
        private int _limit;

        public BoundedQueue(int limit)
        {
            _fixedSizeBuffer = new Queue<T>();
            _limit = limit;
            _bufferLock = new object();

            for (int i = 0; i < _limit; i++)
            {
                _fixedSizeBuffer.Enqueue(null);
            }
        }

        public void AddElementToBuffer(T element)
        {
            lock (_bufferLock)
            {
                _fixedSizeBuffer.Enqueue(element);
                while (_fixedSizeBuffer.Count > _limit)
                {
                    _fixedSizeBuffer.Dequeue();
                }
            }
        }

        public T GetElementAt(int index)
        {
            T element;
            lock (_bufferLock)
            {
                element = _fixedSizeBuffer.ElementAt(_limit - index - 1);
            }
            return element;
        }
    }

мой новый код

public class FixedSizeConcurrentQueue<T> where T : class
{
    private readonly ConcurrentQueue<T> _fixedSizeBuffer;
    private int _maxSize;
    public FixedSizeConcurrentQueue(int maxSize)
    {
        _maxSize = maxSize;
        for (int i = 0; i < _maxSize; i++)
        {
            _fixedSizeBuffer.Enqueue(null);
        }
    }

    public void AddElementToBuffer(T element)
    {
        _fixedSizeBuffer.Enqueue(element);
        while (_fixedSizeBuffer.Count > _maxSize)
        {
            T item;
            _fixedSizeBuffer.TryDequeue(out item);
        }
    }
    public T GetElementAt(int index)
    {
        var element = _fixedSizeBuffer.ElementAt(_maxSize - index - 1);
        return element;
    }
}

Мой вопрос касается функции ElementAt(), или мне лучше назвать ее TryGetElement().
в старом коде, код использовал блокировку для синхронизации различных потоков.
Однако в новом коде я удалил его, так как знаю, что использовать блокировку при параллельной коллекции - плохая практика.
Так что, если индекс не найден, потому что очередь пуста, например, я бы получил исключение.
Так я должен обернуть это попыткой catch?
объясните, пожалуйста, как бы вы это сделали.

1 Ответ

0 голосов
/ 19 января 2019

Ваша переменная maxsize не синхронизируется между потоками, поэтому существует проблема с потоками.Кроме того, ConcurrentQueue уже имеет функцию ElementAtOrDefault, которая автоматически возвращает null, если индекс не существует.

Я бы обновился, чтобы наследовать от ConcurrentQueue самого себя.

public class FixedSizeConcurrentQueue<T> : ConcurrentQueue<T>
{
    public int MaxSize { get; }

    public FixedSizeConcurrentQueue(int maxSize)
    {
        MaxSize = maxSize;
    }

    public new void Enqueue(T obj)
    {
        base.Enqueue(obj);

        while (base.Count > MaxSize)
        {
            T outObj;
            base.TryDequeue(out outObj);
        }
    }

    public T GetElementAt(int index)
    {
        return base.ElementAtOrDefault(index);;
    }
}
...