Is this lock-free .NET queue thread safe?

后端 未结 6 948
野的像风
野的像风 2021-02-06 10:32

My question is, is the class included below for a single-reader single-writer queue class thread-safe? This kind of queue is called lock-free, even if it will block if the queue

6条回答
  •  失恋的感觉
    2021-02-06 10:49

    First, I wonder about the assumption in these two lines of sequential code:

                    node.data[current++] = x;
    
                    // We have to use interlocked, to assure that we incremeent the count 
                    // atomicalluy, because the reader could be reading it.
                    Interlocked.Increment(ref node.count);
    

    What is to say that the new value of node.data[] has been committed to this memory location? It is not stored in a volatile memory address and therefore can be cached if I understand it correctly? Doesn't this potentially lead to a 'dirty' read? There may be other places the same is true, but this one stood out at a glance.

    Second, multi-threaded code that contains the following:

    Thread.Sleep(int);
    

    ... is never a good sign. If it's required then the code is destined to fail, if it isn't required it's a waste. I really wish they would remove this API entirely. Realize that is a request to wait at least that amount of time. With the overhead of context switching your almost certainly going to wait longer, a lot longer.

    Third, I completely don't understand the use of the Interlock API here. Maybe I'm tired and just missing the point; but I can't find the potential thread conflict on both threads reading & writing to the same variable? It would seem that the only use I could find for interlock exchange would be to modify the contents of node.data[] to fix #1 above.

    Lastly it would seem that the implementation is somewhat over-complicated. Am I missing the point of the whole Cursor/Node thing or is it basically doing the same thing as this class? (Note: I haven't tried it and I don't think this is thread safe either, just trying to boil down what I think your doing.)

    class ReaderWriterQueue
    {
        readonly AutoResetEvent _readComplete;
        readonly T[] _buffer;
        readonly int _maxBuffer;
        int _readerPos, _writerPos;
    
        public ReaderWriterQueue(int maxBuffer)
        {
            _readComplete = new AutoResetEvent(true);
            _maxBuffer = maxBuffer;
            _buffer = new T[_maxBuffer];
            _readerPos = _writerPos = 0;
        }
    
        public int Next(int current) { return ++current == _maxBuffer ? 0 : current; }
    
        public bool Read(ref T item)
        {
            if (_readerPos != _writerPos)
            {
                item = _buffer[_readerPos];
                _readerPos = Next(_readerPos);
                return true;
            }
            else
                return false;
        }
    
        public void Write(T item)
        {
            int next = Next(_writerPos);
    
            while (next == _readerPos)
                _readComplete.WaitOne();
    
            _buffer[next] = item;
            _writerPos = next;
        }
    }
    

    So am I totally off-base here and am failing to see the magic in the original class?

    I must admit one thing, I despise Threading. I've seen the best developers fail at it. This article gives a great example on how hard it is to get threading right: http://www.yoda.arachsys.com/csharp/singleton.html

提交回复
热议问题