C#固定大小的ConcurrentQueue在索引处获取元素

时间:2019-01-18 22:03:43

标签: c# concurrency queue thread-safety

我发现一个实现线程安全队列的旧代码。 我尝试使用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()
在旧代码中,代码使用锁来同步不同的线程。
但是,在新代码中,我删除了它,因为我知道在有并发集合时使用锁是一种不好的做法。
因此,例如,如果由于队列为空而未找到索引,则会出现异常。
那么我应该用try catch包裹它吗?
请解释一下怎么做。

1 个答案:

答案 0 :(得分:1)

您的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);;
    }
}