예제 #1
0
        private bool TryDequeueSlow <T>(out T result) where T : unmanaged
        {
            while (true)
            {
                QueueSegment *head = _head;

                if (head->TryDequeue(out result))
                {
                    return(true);
                }

                if (head->_nextSegment == null)
                {
                    result = default;
                    return(false);
                }

                UDebug.Assert(head->_frozen);

                if (head->TryDequeue(out result))
                {
                    return(true);
                }

                _crossSegmentLock.Lock();
                if (head == _head)
                {
                    var next = head->_nextSegment;
                    QueueSegment.Free(head);

                    _head = next;
                }
                _crossSegmentLock.Unlock();
            }
        }
예제 #2
0
        public static void Clear(UnsafeMPMCQueue *queue)
        {
            UDebug.Assert(queue != null);
            UDebug.Assert(queue->_head != null);

            queue->_crossSegmentLock.Lock();
            queue->_tail->EnsureFrozenForEnqueues();

            var segmentsize = INITIAL_SEGMENT_LENGTH;

            if (queue->_fixedSize)
            {
                segmentsize = queue->_tail->Capacity;
            }

            // Free all segments
            var segment = queue->_head;

            do
            {
                var next = segment->_nextSegment;
                QueueSegment.Free(segment);
                segment = next;
            }while (segment != null);

            queue->_tail = queue->_head = QueueSegment.Allocate(segmentsize, queue->_slotStride, queue->_slotOffset);

            queue->_crossSegmentLock.Unlock();
        }
예제 #3
0
        private bool TryEnqueueSlow <T>(T item) where T : unmanaged
        {
            while (true)
            {
                QueueSegment *tail = _tail;

                if (tail->TryEnqueue(item))
                {
                    return(true);
                }

                // Do not create a new segment if the queue has a fixed size.
                if (_fixedSize)
                {
                    return(false);
                }

                _crossSegmentLock.Lock();
                if (tail == _tail)
                {
                    tail->EnsureFrozenForEnqueues();

                    int nextSize = tail->_preserved ? INITIAL_SEGMENT_LENGTH : Math.Min(tail->Capacity * 2, MAX_SEGMENT_LENGTH);
                    var newTail  = QueueSegment.Allocate(nextSize, _slotStride, _slotOffset);

                    tail->_nextSegment = newTail;
                    _tail = newTail;
                }

                _crossSegmentLock.Unlock();
            }
        }
예제 #4
0
        /// <summary>
        /// Creates a Multi-Producer, Multi-Consumer concurrent queue.
        /// </summary>
        /// <param name="segmentSize">The size of a queue segment or the queue capacity when fixedSize = true.</param>
        /// <param name="fixedSize">Creates a queue with a fixed size if true.</param>
        public static UnsafeMPMCQueue *Allocate <T>(int segmentSize = INITIAL_SEGMENT_LENGTH, bool fixedSize = false) where T : unmanaged
        {
            if (segmentSize < 1)
            {
                throw new ArgumentOutOfRangeException(nameof(segmentSize), string.Format(ThrowHelper.ArgumentOutOfRange_MustBePositive, nameof(segmentSize)));
            }

            int slotStride = Marshal.SizeOf(new QueueSlot <T>());
            int slotAlign  = Memory.GetMaxAlignment(sizeof(T), sizeof(int));
            int slotOffset = Memory.RoundToAlignment(sizeof(T), slotAlign);

            var queue = Memory.MallocAndZero <UnsafeMPMCQueue>();

            queue->_typeHandle = typeof(T).TypeHandle.Value;
            queue->_slotStride = slotStride;
            queue->_slotOffset = slotOffset;
            queue->_fixedSize  = fixedSize;
            queue->_tail       = queue->_head = QueueSegment.Allocate(segmentSize, slotStride, slotOffset);

            return(queue);
        }
예제 #5
0
        public static void Free(UnsafeMPMCQueue *queue)
        {
            if (queue == null)
            {
                return;
            }

            // Free all segments
            var segment = queue->_head;

            do
            {
                var next = segment->_nextSegment;
                QueueSegment.Free(segment);
                segment = next;
            }while (segment != null);

            // 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);
        }