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