316 lines
		
	
	
		
			10 KiB
		
	
	
	
		
			C#
		
	
	
		
		
			
		
	
	
			316 lines
		
	
	
		
			10 KiB
		
	
	
	
		
			C#
		
	
	
| 
								 | 
							
								using System.Runtime.CompilerServices;
							 | 
						||
| 
								 | 
							
								using System.Runtime.InteropServices;
							 | 
						||
| 
								 | 
							
								using System.Threading;
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								namespace dotNetty_kcp.thread
							 | 
						||
| 
								 | 
							
								{
							 | 
						||
| 
								 | 
							
								    public class RingBuffer<T>
							 | 
						||
| 
								 | 
							
								    {
							 | 
						||
| 
								 | 
							
								        private readonly T[] _entries;
							 | 
						||
| 
								 | 
							
								        private readonly int _modMask;
							 | 
						||
| 
								 | 
							
								        private Volatile.PaddedLong _consumerCursor = new Volatile.PaddedLong();
							 | 
						||
| 
								 | 
							
								        private Volatile.PaddedLong _producerCursor = new Volatile.PaddedLong();
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								        /// <summary>
							 | 
						||
| 
								 | 
							
								        /// Creates a new RingBuffer with the given capacity
							 | 
						||
| 
								 | 
							
								        /// </summary>
							 | 
						||
| 
								 | 
							
								        /// <param name="capacity">The capacity of the buffer</param>
							 | 
						||
| 
								 | 
							
								        /// <remarks>Only a single thread may attempt to consume at any one time</remarks>
							 | 
						||
| 
								 | 
							
								        public RingBuffer(int capacity)
							 | 
						||
| 
								 | 
							
								        {
							 | 
						||
| 
								 | 
							
								            capacity = NextPowerOfTwo(capacity);
							 | 
						||
| 
								 | 
							
								            _modMask = capacity - 1;
							 | 
						||
| 
								 | 
							
								            _entries = new T[capacity];
							 | 
						||
| 
								 | 
							
								        }
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								        /// <summary>
							 | 
						||
| 
								 | 
							
								        /// The maximum number of items that can be stored
							 | 
						||
| 
								 | 
							
								        /// </summary>
							 | 
						||
| 
								 | 
							
								        public int Capacity
							 | 
						||
| 
								 | 
							
								        {
							 | 
						||
| 
								 | 
							
								            get { return _entries.Length; }
							 | 
						||
| 
								 | 
							
								        }
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								        public T this[long index]
							 | 
						||
| 
								 | 
							
								        {
							 | 
						||
| 
								 | 
							
								            get
							 | 
						||
| 
								 | 
							
								            {
							 | 
						||
| 
								 | 
							
								                unchecked
							 | 
						||
| 
								 | 
							
								                {
							 | 
						||
| 
								 | 
							
								                    return _entries[index & _modMask];
							 | 
						||
| 
								 | 
							
								                }
							 | 
						||
| 
								 | 
							
								            }
							 | 
						||
| 
								 | 
							
								            set
							 | 
						||
| 
								 | 
							
								            {
							 | 
						||
| 
								 | 
							
								                unchecked
							 | 
						||
| 
								 | 
							
								                {
							 | 
						||
| 
								 | 
							
								                    _entries[index & _modMask] = value;
							 | 
						||
| 
								 | 
							
								                }
							 | 
						||
| 
								 | 
							
								            }
							 | 
						||
| 
								 | 
							
								        }
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								        /// <summary>
							 | 
						||
| 
								 | 
							
								        /// Removes an item from the buffer.
							 | 
						||
| 
								 | 
							
								        /// </summary>
							 | 
						||
| 
								 | 
							
								        /// <returns>The next available item</returns>
							 | 
						||
| 
								 | 
							
								        public T Dequeue()
							 | 
						||
| 
								 | 
							
								        {
							 | 
						||
| 
								 | 
							
								            var next = _consumerCursor.ReadAcquireFence() + 1;
							 | 
						||
| 
								 | 
							
								            while (_producerCursor.ReadAcquireFence() < next
							 | 
						||
| 
								 | 
							
								            ) // makes sure we read the data from _entries after we have read the producer cursor
							 | 
						||
| 
								 | 
							
								            {
							 | 
						||
| 
								 | 
							
								                Thread.SpinWait(1);
							 | 
						||
| 
								 | 
							
								            }
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								            var result = this[next];
							 | 
						||
| 
								 | 
							
								            _consumerCursor
							 | 
						||
| 
								 | 
							
								                .WriteReleaseFence(
							 | 
						||
| 
								 | 
							
								                    next); // makes sure we read the data from _entries before we update the consumer cursor
							 | 
						||
| 
								 | 
							
								            return result;
							 | 
						||
| 
								 | 
							
								        }
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								        /// <summary>
							 | 
						||
| 
								 | 
							
								        /// Attempts to remove an items from the queue
							 | 
						||
| 
								 | 
							
								        /// </summary>
							 | 
						||
| 
								 | 
							
								        /// <param name="obj">the items</param>
							 | 
						||
| 
								 | 
							
								        /// <returns>True if successful</returns>
							 | 
						||
| 
								 | 
							
								        public bool TryDequeue(out T obj)
							 | 
						||
| 
								 | 
							
								        {
							 | 
						||
| 
								 | 
							
								            var next = _consumerCursor.ReadAcquireFence() + 1;
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								            if (_producerCursor.ReadAcquireFence() < next)
							 | 
						||
| 
								 | 
							
								            {
							 | 
						||
| 
								 | 
							
								                obj = default(T);
							 | 
						||
| 
								 | 
							
								                return false;
							 | 
						||
| 
								 | 
							
								            }
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								            obj = Dequeue();
							 | 
						||
| 
								 | 
							
								            return true;
							 | 
						||
| 
								 | 
							
								        }
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								        /// <summary>
							 | 
						||
| 
								 | 
							
								        /// Add an item to the buffer
							 | 
						||
| 
								 | 
							
								        /// </summary>
							 | 
						||
| 
								 | 
							
								        /// <param name="item"></param>
							 | 
						||
| 
								 | 
							
								        public void Enqueue(T item)
							 | 
						||
| 
								 | 
							
								        {
							 | 
						||
| 
								 | 
							
								            var next = _producerCursor.ReadAcquireFence() + 1;
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								            long wrapPoint = next - _entries.Length;
							 | 
						||
| 
								 | 
							
								            long min = _consumerCursor.ReadAcquireFence();
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								            while (wrapPoint > min)
							 | 
						||
| 
								 | 
							
								            {
							 | 
						||
| 
								 | 
							
								                min = _consumerCursor.ReadAcquireFence();
							 | 
						||
| 
								 | 
							
								                Thread.SpinWait(1);
							 | 
						||
| 
								 | 
							
								            }
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								            this[next] = item;
							 | 
						||
| 
								 | 
							
								            _producerCursor
							 | 
						||
| 
								 | 
							
								                .WriteReleaseFence(
							 | 
						||
| 
								 | 
							
								                    next); // makes sure we write the data in _entries before we update the producer cursor
							 | 
						||
| 
								 | 
							
								        }
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								        /// <summary>
							 | 
						||
| 
								 | 
							
								        /// Add an item to the buffer
							 | 
						||
| 
								 | 
							
								        /// </summary>
							 | 
						||
| 
								 | 
							
								        /// <param name="item"></param>
							 | 
						||
| 
								 | 
							
								        public bool tryEnqueue(T item)
							 | 
						||
| 
								 | 
							
								        {
							 | 
						||
| 
								 | 
							
								            var next = _producerCursor.ReadAcquireFence() + 1;
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								            long wrapPoint = next - _entries.Length;
							 | 
						||
| 
								 | 
							
								            long min = _consumerCursor.ReadAcquireFence();
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								            if (wrapPoint>min)
							 | 
						||
| 
								 | 
							
								            {
							 | 
						||
| 
								 | 
							
								                return false;
							 | 
						||
| 
								 | 
							
								            }
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								            this[next] = item;
							 | 
						||
| 
								 | 
							
								            _producerCursor
							 | 
						||
| 
								 | 
							
								                .WriteReleaseFence(
							 | 
						||
| 
								 | 
							
								                    next); // makes sure we write the data in _entries before we update the producer cursor
							 | 
						||
| 
								 | 
							
								            return true;
							 | 
						||
| 
								 | 
							
								        }
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								        /// <summary>
							 | 
						||
| 
								 | 
							
								        /// The number of items in the buffer
							 | 
						||
| 
								 | 
							
								        /// </summary>
							 | 
						||
| 
								 | 
							
								        /// <remarks>for indicative purposes only, may contain stale data</remarks>
							 | 
						||
| 
								 | 
							
								        public int Count
							 | 
						||
| 
								 | 
							
								        {
							 | 
						||
| 
								 | 
							
								            get { return (int) (_producerCursor.ReadFullFence() - _consumerCursor.ReadFullFence()); }
							 | 
						||
| 
								 | 
							
								        }
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								        private static int NextPowerOfTwo(int x)
							 | 
						||
| 
								 | 
							
								        {
							 | 
						||
| 
								 | 
							
								            var result = 2;
							 | 
						||
| 
								 | 
							
								            while (result < x)
							 | 
						||
| 
								 | 
							
								            {
							 | 
						||
| 
								 | 
							
								                result <<= 1;
							 | 
						||
| 
								 | 
							
								            }
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								            return result;
							 | 
						||
| 
								 | 
							
								        }
							 | 
						||
| 
								 | 
							
								    }
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								    public static class Volatile
							 | 
						||
| 
								 | 
							
								    {
							 | 
						||
| 
								 | 
							
								        private const int CacheLineSize = 64;
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								        [StructLayout(LayoutKind.Explicit, Size = CacheLineSize * 2)]
							 | 
						||
| 
								 | 
							
								        public struct PaddedLong
							 | 
						||
| 
								 | 
							
								        {
							 | 
						||
| 
								 | 
							
								            [FieldOffset(CacheLineSize)] private long _value;
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								            /// <summary>
							 | 
						||
| 
								 | 
							
								            /// Create a new <see cref="PaddedLong"/> with the given initial value.
							 | 
						||
| 
								 | 
							
								            /// </summary>
							 | 
						||
| 
								 | 
							
								            /// <param name="value">Initial value</param>
							 | 
						||
| 
								 | 
							
								            public PaddedLong(long value)
							 | 
						||
| 
								 | 
							
								            {
							 | 
						||
| 
								 | 
							
								                _value = value;
							 | 
						||
| 
								 | 
							
								            }
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								            /// <summary>
							 | 
						||
| 
								 | 
							
								            /// Read the value without applying any fence
							 | 
						||
| 
								 | 
							
								            /// </summary>
							 | 
						||
| 
								 | 
							
								            /// <returns>The current value</returns>
							 | 
						||
| 
								 | 
							
								            public long ReadUnfenced()
							 | 
						||
| 
								 | 
							
								            {
							 | 
						||
| 
								 | 
							
								                return _value;
							 | 
						||
| 
								 | 
							
								            }
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								            /// <summary>
							 | 
						||
| 
								 | 
							
								            /// Read the value applying acquire fence semantic
							 | 
						||
| 
								 | 
							
								            /// </summary>
							 | 
						||
| 
								 | 
							
								            /// <returns>The current value</returns>
							 | 
						||
| 
								 | 
							
								            public long ReadAcquireFence()
							 | 
						||
| 
								 | 
							
								            {
							 | 
						||
| 
								 | 
							
								                var value = _value;
							 | 
						||
| 
								 | 
							
								                Thread.MemoryBarrier();
							 | 
						||
| 
								 | 
							
								                return value;
							 | 
						||
| 
								 | 
							
								            }
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								            /// <summary>
							 | 
						||
| 
								 | 
							
								            /// Read the value applying full fence semantic
							 | 
						||
| 
								 | 
							
								            /// </summary>
							 | 
						||
| 
								 | 
							
								            /// <returns>The current value</returns>
							 | 
						||
| 
								 | 
							
								            public long ReadFullFence()
							 | 
						||
| 
								 | 
							
								            {
							 | 
						||
| 
								 | 
							
								                Thread.MemoryBarrier();
							 | 
						||
| 
								 | 
							
								                return _value;
							 | 
						||
| 
								 | 
							
								            }
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								            /// <summary>
							 | 
						||
| 
								 | 
							
								            /// Read the value applying a compiler only fence, no CPU fence is applied
							 | 
						||
| 
								 | 
							
								            /// </summary>
							 | 
						||
| 
								 | 
							
								            /// <returns>The current value</returns>
							 | 
						||
| 
								 | 
							
								            [MethodImpl(MethodImplOptions.NoOptimization)]
							 | 
						||
| 
								 | 
							
								            public long ReadCompilerOnlyFence()
							 | 
						||
| 
								 | 
							
								            {
							 | 
						||
| 
								 | 
							
								                return _value;
							 | 
						||
| 
								 | 
							
								            }
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								            /// <summary>
							 | 
						||
| 
								 | 
							
								            /// Write the value applying release fence semantic
							 | 
						||
| 
								 | 
							
								            /// </summary>
							 | 
						||
| 
								 | 
							
								            /// <param name="newValue">The new value</param>
							 | 
						||
| 
								 | 
							
								            public void WriteReleaseFence(long newValue)
							 | 
						||
| 
								 | 
							
								            {
							 | 
						||
| 
								 | 
							
								                Thread.MemoryBarrier();
							 | 
						||
| 
								 | 
							
								                _value = newValue;
							 | 
						||
| 
								 | 
							
								            }
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								            /// <summary>
							 | 
						||
| 
								 | 
							
								            /// Write the value applying full fence semantic
							 | 
						||
| 
								 | 
							
								            /// </summary>
							 | 
						||
| 
								 | 
							
								            /// <param name="newValue">The new value</param>
							 | 
						||
| 
								 | 
							
								            public void WriteFullFence(long newValue)
							 | 
						||
| 
								 | 
							
								            {
							 | 
						||
| 
								 | 
							
								                Thread.MemoryBarrier();
							 | 
						||
| 
								 | 
							
								                _value = newValue;
							 | 
						||
| 
								 | 
							
								            }
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								            /// <summary>
							 | 
						||
| 
								 | 
							
								            /// Write the value applying a compiler fence only, no CPU fence is applied
							 | 
						||
| 
								 | 
							
								            /// </summary>
							 | 
						||
| 
								 | 
							
								            /// <param name="newValue">The new value</param>
							 | 
						||
| 
								 | 
							
								            [MethodImpl(MethodImplOptions.NoOptimization)]
							 | 
						||
| 
								 | 
							
								            public void WriteCompilerOnlyFence(long newValue)
							 | 
						||
| 
								 | 
							
								            {
							 | 
						||
| 
								 | 
							
								                _value = newValue;
							 | 
						||
| 
								 | 
							
								            }
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								            /// <summary>
							 | 
						||
| 
								 | 
							
								            /// Write without applying any fence
							 | 
						||
| 
								 | 
							
								            /// </summary>
							 | 
						||
| 
								 | 
							
								            /// <param name="newValue">The new value</param>
							 | 
						||
| 
								 | 
							
								            public void WriteUnfenced(long newValue)
							 | 
						||
| 
								 | 
							
								            {
							 | 
						||
| 
								 | 
							
								                _value = newValue;
							 | 
						||
| 
								 | 
							
								            }
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								            /// <summary>
							 | 
						||
| 
								 | 
							
								            /// Atomically set the value to the given updated value if the current value equals the comparand
							 | 
						||
| 
								 | 
							
								            /// </summary>
							 | 
						||
| 
								 | 
							
								            /// <param name="newValue">The new value</param>
							 | 
						||
| 
								 | 
							
								            /// <param name="comparand">The comparand (expected value)</param>
							 | 
						||
| 
								 | 
							
								            /// <returns></returns>
							 | 
						||
| 
								 | 
							
								            public bool AtomicCompareExchange(long newValue, long comparand)
							 | 
						||
| 
								 | 
							
								            {
							 | 
						||
| 
								 | 
							
								                return Interlocked.CompareExchange(ref _value, newValue, comparand) == comparand;
							 | 
						||
| 
								 | 
							
								            }
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								            /// <summary>
							 | 
						||
| 
								 | 
							
								            /// Atomically set the value to the given updated value
							 | 
						||
| 
								 | 
							
								            /// </summary>
							 | 
						||
| 
								 | 
							
								            /// <param name="newValue">The new value</param>
							 | 
						||
| 
								 | 
							
								            /// <returns>The original value</returns>
							 | 
						||
| 
								 | 
							
								            public long AtomicExchange(long newValue)
							 | 
						||
| 
								 | 
							
								            {
							 | 
						||
| 
								 | 
							
								                return Interlocked.Exchange(ref _value, newValue);
							 | 
						||
| 
								 | 
							
								            }
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								            /// <summary>
							 | 
						||
| 
								 | 
							
								            /// Atomically add the given value to the current value and return the sum
							 | 
						||
| 
								 | 
							
								            /// </summary>
							 | 
						||
| 
								 | 
							
								            /// <param name="delta">The value to be added</param>
							 | 
						||
| 
								 | 
							
								            /// <returns>The sum of the current value and the given value</returns>
							 | 
						||
| 
								 | 
							
								            public long AtomicAddAndGet(long delta)
							 | 
						||
| 
								 | 
							
								            {
							 | 
						||
| 
								 | 
							
								                return Interlocked.Add(ref _value, delta);
							 | 
						||
| 
								 | 
							
								            }
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								            /// <summary>
							 | 
						||
| 
								 | 
							
								            /// Atomically increment the current value and return the new value
							 | 
						||
| 
								 | 
							
								            /// </summary>
							 | 
						||
| 
								 | 
							
								            /// <returns>The incremented value.</returns>
							 | 
						||
| 
								 | 
							
								            public long AtomicIncrementAndGet()
							 | 
						||
| 
								 | 
							
								            {
							 | 
						||
| 
								 | 
							
								                return Interlocked.Increment(ref _value);
							 | 
						||
| 
								 | 
							
								            }
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								            /// <summary>
							 | 
						||
| 
								 | 
							
								            /// Atomically increment the current value and return the new value
							 | 
						||
| 
								 | 
							
								            /// </summary>
							 | 
						||
| 
								 | 
							
								            /// <returns>The decremented value.</returns>
							 | 
						||
| 
								 | 
							
								            public long AtomicDecrementAndGet()
							 | 
						||
| 
								 | 
							
								            {
							 | 
						||
| 
								 | 
							
								                return Interlocked.Decrement(ref _value);
							 | 
						||
| 
								 | 
							
								            }
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								            /// <summary>
							 | 
						||
| 
								 | 
							
								            /// Returns the string representation of the current value.
							 | 
						||
| 
								 | 
							
								            /// </summary>
							 | 
						||
| 
								 | 
							
								            /// <returns>the string representation of the current value.</returns>
							 | 
						||
| 
								 | 
							
								            public override string ToString()
							 | 
						||
| 
								 | 
							
								            {
							 | 
						||
| 
								 | 
							
								                var value = ReadFullFence();
							 | 
						||
| 
								 | 
							
								                return value.ToString();
							 | 
						||
| 
								 | 
							
								            }
							 | 
						||
| 
								 | 
							
								        }
							 | 
						||
| 
								 | 
							
								    }
							 | 
						||
| 
								 | 
							
								}
							 |