/// <summary>
        /// Closes the shared memory queue currently opened.
        /// </summary>
        public void Close()
        {
            if (mMemoryMappedViewAccessor != null)
            {
                if (mQueueHeader != null)
                {
                    mMemoryMappedViewAccessor.SafeMemoryMappedViewHandle.ReleasePointer();
                    mQueueHeader = null;
                }

                mMemoryMappedViewAccessor.Dispose();
                mMemoryMappedViewAccessor = null;
            }

            if (mMemoryMappedFile != null)
            {
                mMemoryMappedFile.Dispose();
                mMemoryMappedFile = null;
            }

            mQueueHeader         = null;
            mFirstBlockInMemory  = null;
            mFirstBlockUnderRead = null;
            mNumberOfBlocks      = 0;
            mBufferSize          = 0;
            mBlockSize           = 0;
            mInitialized         = false;
        }
        /// <summary>
        /// Creates a new shared memory queue (only supported on the full .NET framework).
        /// </summary>
        /// <param name="name">Name of the shared memory region to create the queue in.</param>
        /// <param name="bufferSize">Size of a buffer in the shared memory queue (in bytes).</param>
        /// <param name="numberOfBlocks">Number of blocks the queue should keep.</param>
        /// <exception cref="NotSupportedException">This method is not supported on the current platform/framework.</exception>
        /// <remarks>
        /// This method creates a new queue in a shared memory region specified by the given name and the given size.
        /// </remarks>
        public void Create(string name, int bufferSize, int numberOfBlocks)
        {
#if NETFRAMEWORK
            if (name == null)
            {
                throw new ArgumentNullException(nameof(name));
            }
            if (bufferSize < 0)
            {
                throw new ArgumentOutOfRangeException(nameof(bufferSize), "The block size must be positive.");
            }
            if (numberOfBlocks < 0)
            {
                throw new ArgumentOutOfRangeException(nameof(numberOfBlocks), "The number of blocks must be positive.");
            }

            // close currently opened queue, if necessary
            Close();

            mNumberOfBlocks = numberOfBlocks;
            mBufferSize     = bufferSize;
            // ensure that the block sizes are a multiple of the cache line size to avoid false sharing
            mBlockSize       = (sizeof(QueueBlock) + mBufferSize + CacheLineSize - 1) & ~(CacheLineSize - 1);
            mQueueHeaderSize = (sizeof(QueueHeader) + CacheLineSize - 1) & ~(CacheLineSize - 1);
            long dataSize        = (long)mNumberOfBlocks * mBlockSize;
            long totalBufferSize = mQueueHeaderSize + dataSize;

            // create the shared memory region
            string queueName = $"{name} - Shared Memory";
            mMemoryMappedFile = MemoryMappedFile.CreateNew(
                queueName,
                totalBufferSize,
                MemoryMappedFileAccess.ReadWrite,
                MemoryMappedFileOptions.None,
                sMemoryMappedFileSecurity,
                HandleInheritability.None);
            mMemoryMappedViewAccessor = mMemoryMappedFile.CreateViewAccessor();

            // get pointer to the buffer
            byte *ptr = null;
            mMemoryMappedViewAccessor.SafeMemoryMappedViewHandle.AcquirePointer(ref ptr);
            mQueueHeader        = (QueueHeader *)ptr;
            mFirstBlockInMemory = (QueueBlock *)((byte *)mQueueHeader + mQueueHeaderSize);

            // init the queue
            InitQueue();

            // the queue is initialized now
            mFirstBlockUnderRead = null;
            mInitialized         = true;
#else
            throw new NotSupportedException("The Created() method is only supported on the full .NET framework.");
#endif
        }
        /// <summary>
        /// Opens an existing queue in the shared memory region with the specified name.
        /// </summary>
        /// <param name="name">Name of the shared memory region to open.</param>
        public void Open(string name)
        {
            // close currently opened queue, if necessary
            Close();

            try
            {
                // open the shared memory region the queue resides in
                string queueName = $"{name} - Shared Memory";
                mMemoryMappedFile         = MemoryMappedFile.OpenExisting(queueName, MemoryMappedFileRights.ReadWrite);
                mMemoryMappedViewAccessor = mMemoryMappedFile.CreateViewAccessor();

                // get pointer to the buffer in shared memory
                byte *ptr = null;
                mMemoryMappedViewAccessor.SafeMemoryMappedViewHandle.AcquirePointer(ref ptr);
                mQueueHeader = (QueueHeader *)ptr;

                // check the queue's signature
                // (for an explanation why 'ALVA' see InitQueue()
                if (mQueueHeader->Signature[0] != 'A' ||
                    mQueueHeader->Signature[1] != 'L' ||
                    mQueueHeader->Signature[2] != 'V' ||
                    mQueueHeader->Signature[3] != 'A')
                {
                    throw new InvalidDataException("Shared region does not start with the magic word 'ALVA'.");
                }

                // read administrative information from the queue's header
                mNumberOfBlocks     = mQueueHeader->NumberOfBlocks;
                mBufferSize         = mQueueHeader->BufferSize;
                mBlockSize          = mQueueHeader->BlockSize;
                mQueueHeaderSize    = (sizeof(QueueHeader) + CacheLineSize - 1) & ~(CacheLineSize - 1);
                mFirstBlockInMemory = (QueueBlock *)((byte *)mQueueHeader + mQueueHeaderSize);

                // the queue is initialized now!
                mFirstBlockUnderRead = null;
                mInitialized         = true;
            }
            catch (Exception)
            {
                Close();
                throw;
            }
        }