コード例 #1
0
        private static void SplitQueue(UnsafeSPSCQueue *q)
        {
            //Wrap tail back to 0
            for (int i = 0; i < 5; i++)
            {
                UnsafeSPSCQueue.Enqueue(q, 111);
            }

            //First half
            for (int i = 0; i < 5; i++)
            {
                UnsafeSPSCQueue.Enqueue(q, i);
            }

            //Move head by 5
            for (int i = 0; i < 5; i++)
            {
                UnsafeSPSCQueue.Dequeue <int>(q);
            }

            //Second half (head and tail are now both 5)
            for (int i = 5; i < 10; i++)
            {
                UnsafeSPSCQueue.Enqueue(q, i);
            }

            //Circular buffer now "ends" in the middle of the underlying array
        }
コード例 #2
0
        public static void Clear(UnsafeSPSCQueue *queue)
        {
            UDebug.Assert(queue != null);
            UDebug.Assert(queue->_items.Ptr != null);

            queue->_headAndTail = new HeadAndTail();
        }
コード例 #3
0
        /// <summary>
        /// Allocates a new SPSCRingbuffer. Capacity will be set to a power of 2.
        /// </summary>
        public static UnsafeSPSCQueue *Allocate <T>(int capacity) where T : unmanaged
        {
            if (capacity < 1)
            {
                throw new ArgumentOutOfRangeException(nameof(capacity), string.Format(ThrowHelper.ArgumentOutOfRange_MustBePositive, nameof(capacity)));
            }

            // Requires one extra element to distinguish between empty and full queue.
            capacity++;

            int stride = sizeof(T);

            var alignment   = Memory.GetAlignment(stride);
            var sizeOfQueue = Memory.RoundToAlignment(sizeof(UnsafeSPSCQueue), alignment);
            var sizeOfArray = stride * capacity;

            var ptr = Memory.MallocAndZero(sizeOfQueue + sizeOfArray, alignment);

            UnsafeSPSCQueue *queue = (UnsafeSPSCQueue *)ptr;

            // initialize fixed buffer from same block of memory as the stack
            UnsafeBuffer.InitFixed(&queue->_items, (byte *)ptr + sizeOfQueue, capacity, stride);

            queue->_headAndTail = new HeadAndTail();
            queue->_typeHandle  = typeof(T).TypeHandle.Value;

            return(queue);
        }
コード例 #4
0
        public static int GetCapacity(UnsafeSPSCQueue *queue)
        {
            UDebug.Assert(queue != null);
            UDebug.Assert(queue->_items.Ptr != null);

            return(queue->_items.Length - 1);
        }
コード例 #5
0
 internal Enumerator(UnsafeSPSCQueue *queue)
 {
     _queue     = queue;
     _index     = -1;
     _current   = default;
     _headStart = Volatile.Read(ref queue->_headAndTail.Head);
     _capacity  = queue->_items.Length;
 }
コード例 #6
0
        /// <summary>
        /// Creates an enumerator for the current snapshot of the queue.
        /// </summary>
        public static Enumerator <T> GetEnumerator <T>(UnsafeSPSCQueue *queue) where T : unmanaged
        {
            UDebug.Assert(queue != null);
            UDebug.Assert(queue->_items.Ptr != null);
            UDebug.Assert(typeof(T).TypeHandle.Value == queue->_typeHandle);

            return(new Enumerator <T>(queue));
        }
コード例 #7
0
        public static bool IsEmpty <T>(UnsafeSPSCQueue *queue) where T : unmanaged
        {
            UDebug.Assert(queue != null);
            UDebug.Assert(queue->_items.Ptr != null);
            UDebug.Assert(typeof(T).TypeHandle.Value == queue->_typeHandle);

            var nextHead = Volatile.Read(ref queue->_headAndTail.Head) + 1;

            return(Volatile.Read(ref queue->_headAndTail.Tail) < nextHead);
        }
コード例 #8
0
        public static void Free(UnsafeSPSCQueue *queue)
        {
            if (queue == null)
            {
                return;
            }

            // clear queue memory (just in case)
            *queue = default;

            // free queue memory, if this is a fixed queue it frees the items memory at the same time
            Memory.Free(queue);
        }
コード例 #9
0
        public static int GetCount(UnsafeSPSCQueue *queue)
        {
            UDebug.Assert(queue != null);
            UDebug.Assert(queue->_items.Ptr != null);

            var head = Volatile.Read(ref queue->_headAndTail.Head);
            var tail = Volatile.Read(ref queue->_headAndTail.Tail);

            var dif = tail - head;

            if (dif < 0)
            {
                dif += queue->_items.Length;
            }

            return(dif);
        }
コード例 #10
0
        /// <summary>
        /// Peeks the next item in the queue. Blocks the thread until an item is available.
        /// </summary>
        public static T Peek <T>(UnsafeSPSCQueue *queue) where T : unmanaged
        {
            UDebug.Assert(queue != null);
            UDebug.Assert(queue->_items.Ptr != null);
            UDebug.Assert(typeof(T).TypeHandle.Value == queue->_typeHandle);

            SpinWait spinner = default;
            var      head    = Volatile.Read(ref queue->_headAndTail.Head);

            // Queue empty
            if (Volatile.Read(ref queue->_headAndTail.Tail) == head)
            {
                spinner.SpinOnce();
            }

            return(*queue->_items.Element <T>(head));
        }
コード例 #11
0
        public static bool TryPeek <T>(UnsafeSPSCQueue *queue, out T result) where T : unmanaged
        {
            UDebug.Assert(queue != null);
            UDebug.Assert(queue->_items.Ptr != null);
            UDebug.Assert(typeof(T).TypeHandle.Value == queue->_typeHandle);

            var head = Volatile.Read(ref queue->_headAndTail.Head);

            // Queue empty
            if (Volatile.Read(ref queue->_headAndTail.Tail) == head)
            {
                result = default;
                return(false);
            }

            result = *queue->_items.Element <T>(head);

            return(true);
        }
コード例 #12
0
        /// <summary>
        /// Returns a snapshot of the elements in the queue.
        /// </summary>
        /// <returns></returns>
        public static T[] ToArray <T>(UnsafeSPSCQueue *queue) where T : unmanaged
        {
            UDebug.Assert(queue != null);
            UDebug.Assert(queue->_items.Ptr != null);
            UDebug.Assert(typeof(T).TypeHandle.Value == queue->_typeHandle);

            var head = Volatile.Read(ref queue->_headAndTail.Head);
            var tail = Volatile.Read(ref queue->_headAndTail.Tail);

            var count = tail - head;

            if (count < 0)
            {
                count += queue->_items.Length;
            }

            if (count <= 0)
            {
                return(Array.Empty <T>());
            }

            var arr = new T[count];

            int numToCopy    = count;
            int bufferLength = queue->_items.Length;
            int ihead        = head;

            int firstPart = Math.Min(bufferLength - ihead, numToCopy);

            fixed(void *ptr = arr)
            {
                UnsafeBuffer.CopyTo <T>(queue->_items, ihead, ptr, 0, firstPart);
                numToCopy -= firstPart;

                if (numToCopy > 0)
                {
                    UnsafeBuffer.CopyTo <T>(queue->_items, 0, ptr, 0 + bufferLength - ihead, numToCopy);
                }
            }

            return(arr);
        }
コード例 #13
0
        /// <summary>
        /// Tries to enqueue an item in the queue. Returns false if there's no space in the queue.
        /// </summary>
        public static bool TryEnqueue <T>(UnsafeSPSCQueue *queue, T item) where T : unmanaged
        {
            UDebug.Assert(queue != null);
            UDebug.Assert(queue->_items.Ptr != null);
            UDebug.Assert(typeof(T).TypeHandle.Value == queue->_typeHandle);

            var tail     = Volatile.Read(ref queue->_headAndTail.Tail);
            var nextTail = GetNext(tail, queue->_items.Length);

            // Full Queue
            if (nextTail == Volatile.Read(ref queue->_headAndTail.Head))
            {
                return(false);
            }

            *queue->_items.Element <T>(tail) = item;

            Volatile.Write(ref queue->_headAndTail.Tail, nextTail);
            return(true);
        }
コード例 #14
0
        /// <summary>
        /// Enqueues an item in the queue. Blocks the thread until there is space in the queue.
        /// </summary>
        public static void Enqueue <T>(UnsafeSPSCQueue *queue, T item) where T : unmanaged
        {
            UDebug.Assert(queue != null);
            UDebug.Assert(queue->_items.Ptr != null);
            UDebug.Assert(typeof(T).TypeHandle.Value == queue->_typeHandle);

            SpinWait spinner  = default;
            var      tail     = Volatile.Read(ref queue->_headAndTail.Tail);
            var      nextTail = GetNext(tail, queue->_items.Length);


            // Full Queue
            while (nextTail == Volatile.Read(ref queue->_headAndTail.Head))
            {
                spinner.SpinOnce();
            }

            *queue->_items.Element <T>(tail) = item;

            Volatile.Write(ref queue->_headAndTail.Tail, nextTail);
        }
コード例 #15
0
        /// <summary>
        /// Dequeues an item from the queue. Blocks the thread until there is space in the queue.
        /// </summary>
        public static T Dequeue <T>(UnsafeSPSCQueue *queue) where T : unmanaged
        {
            UDebug.Assert(queue != null);
            UDebug.Assert(queue->_items.Ptr != null);
            UDebug.Assert(typeof(T).TypeHandle.Value == queue->_typeHandle);

            SpinWait spinner = default;
            var      head    = Volatile.Read(ref queue->_headAndTail.Head);

            // Queue empty
            while (Volatile.Read(ref queue->_headAndTail.Tail) == head)
            {
                spinner.SpinOnce();
            }

            var result   = queue->_items.Element <T>(head);
            var nextHead = GetNext(head, queue->_items.Length);

            Volatile.Write(ref queue->_headAndTail.Head, nextHead);

            return(*result);
        }
コード例 #16
0
 public NativeSPSCQueue(int capacity)
 {
     m_inner = UnsafeSPSCQueue.Allocate <T>(capacity);
 }
コード例 #17
0
 public void Dispose()
 {
     UnsafeSPSCQueue.Free(m_inner);
     m_inner = null;
 }