简体   繁体   English

线程安全的有限大小队列

[英]Thread safe limited size queue

I'm trying to write a subj queue, but I get deadlocks and other multithreading problems. 我正在尝试写一个subj队列,但遇到死锁和其他多线程问题。 I want to use Interlocked.CompareExchange to avoid lock usage. 我想使用Interlocked.CompareExchange避免使用lock But this code doesn't work as expected: it just wipe entire Queue. 但是此代码无法按预期工作:只会擦除整个Queue。 What am I doing wrong here? 我在这里做错了什么?

public class FixedSizedQueue<T> : IEnumerable<T>
{
    readonly ConcurrentQueue<T> _queue = new ConcurrentQueue<T>();
    public int Limit { get; set; }

    public FixedSizedQueue(int limit)
    {
        Limit = limit;
    }

    public void Enqueue(T obj)
    {
        _queue.Enqueue(obj);
        if (_queue.Count <= Limit)
            return;
        int count = _queue.Count;
        if (_queue.Count != Interlocked.CompareExchange(ref count, count, _queue.Count))
        {
            T overflow;
            while (_queue.TryDequeue(out overflow))
            {

            }
        }
    }

    public T[] ToArray()
    {
        return _queue.ToArray();
    }

    public IEnumerator<T> GetEnumerator()
    {
        return _queue.GetEnumerator();
    }

    IEnumerator IEnumerable.GetEnumerator()
    {
        return GetEnumerator();
    }
}

Maybe I just need another thread that will just cut the queue... 也许我只需要另一个线程即可削减队列...

Interlocked.CompareExchange is meaningless on stack variable count , as it is accessed from single thread. Interlocked.CompareExchange对堆栈变量count没有意义,因为它是从单线程访问的。 As I guess, you tried to use this method on _queue.Count , but it failed to be compiled because .Count is a property, not a simple variable. 我猜想,您尝试在_queue.Count上使用此方法,但由于.Count是属性而不是简单变量,因此无法编译。 So you need to define counter in your class. 因此,你需要在你的类定义计数器。

public class FixedSizedQueue<T> : IEnumerable<T>
{
    readonly ConcurrentQueue<T> _queue = new ConcurrentQueue<T>();
    int CountShadow = 0; // Counter for check constraints.
    public int Limit { get; set; }

    public FixedSizedQueue(int limit)
    {
        Limit = limit;
    }

    public void Enqueue(T obj)
    {
        /* Update shadow counter first for check constraints. */
        int count = CountShadow;
        while(true)
        {
             if(count => Limit) return; // Adding element would violate constraint
             int countOld = Interlocked.CompareExchange(ref CountShadow, count, count + 1);
             if(countOld == count) break; //Successful update
             count = countOld;
        }
        _queue.Enqueue(obj); // This will update real counter.
    }
    ...
}

Also, you need to set your own setter for Limit property, which would maintain invariant CountShadow <= Limit . 另外,您需要为Limit属性设置自己的设置器,该设置器将保持CountShadow <= Limit不变。 Or just forbid user to set that property after object's construction. 或者只是禁止用户在对象构造后设置该属性。

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM