/// <summary> /// Writes the structure to the next available node for writing. /// </summary> /// <typeparam name="T">The structure type to be written.</typeparam> /// <param name="source">The structure to be written.</param> /// <param name="timeout">The maximum number of milliseconds to wait for a node to become available for writing. Defaults to 1000 (ms).</param> /// <exception cref="ArgumentOutOfRangeException">The size of the <typeparamref name="T"/> structure is larger than <see cref="NodeBufferSize"/>.</exception> /// <returns>The number of bytes written. The value is larger than zero if successful.</returns> public virtual int Write <T>(ref T source, int timeout = 1000) where T : struct { int structSize = Polyfill.GetMarshalSizeOf <T>(); if (structSize > NodeBufferSize) { throw new ArgumentOutOfRangeException("T", string.Format(RS.StructureSizeGtNodeBufferSize, typeof(T).Name)); } // Attempt to retrieve a node for writing Node *node = GetNodeForWriting(timeout); if (node == null) { return(0); } // Copy the data using the MemoryMappedViewAccessor base.Write <T>(ref source, node->Offset); node->AmountWritten = structSize; // Return the node for further writing PostNode(node); return(structSize); }
/// <summary> /// Reads the next available node for reading into the a structure. /// </summary> /// <typeparam name="T">The structure type to be read.</typeparam> /// <param name="destination">The resulting structure, if successful. Otherwise, `default(T)`.</param> /// <param name="timeout">The maximum number of milliseconds to wait for a node to become available for reading. Defaults to 1000 (ms).</param> /// <exception cref="ArgumentOutOfRangeException">If the size of <typeparamref name="T"/> is larger than <see cref="NodeBufferSize"/>.</exception> /// <returns>The number of bytes read.</returns> public virtual int Read <T>(out T destination, int timeout = 1000) where T : struct { int structSize = Polyfill.GetMarshalSizeOf <T>(); if (structSize > NodeBufferSize) { throw new ArgumentOutOfRangeException("T", string.Format(RS.StructureSizeGtNodeBufferSize, typeof(T).Name)); } // Attempt to retrieve a node Node *node = GetNodeForReading(timeout); if (node == null) { destination = default(T); return(0); } // Copy the data using the MemoryMappedViewAccessor base.Read <T>(out destination, node->Offset); // Return the node for further writing ReturnNode(node); return(structSize); }
/// <summary> /// Opens an existing shared memory array with the name specified. /// </summary> /// <param name="name">The name of the shared memory array to open.</param> /// <exception cref="ArgumentOutOfRangeException"> /// The shared memory location specified by <paramref name="name"/> does not have a <see cref="SharedBuffer.BufferSize"/> that is evenly /// divisible by the size of <typeparamref name="T"/>. /// </exception> public SharedList(string name) : base(name, 0, false) { _elementSize = Polyfill.GetMarshalSizeOf <T>(); Open(); }
/// <summary> /// Creates the shared memory array with the specified name. /// </summary> /// <param name="name">The name of the shared memory array to be created.</param> /// <param name="length">The number of elements to make room for within the shared memory array.</param> public SharedList(string name, int length) : base(name, Polyfill.GetMarshalSizeOf <T>() * length, true) { Length = length; _elementSize = Polyfill.GetMarshalSizeOf <T>(); Open(); }
private CircularBuffer(string name, int nodeCount, int nodeBufferSize, bool ownsSharedMemory) : base(name, Polyfill.GetMarshalSizeOf <NodeHeader>() + (Polyfill.GetMarshalSizeOf <Node>() * nodeCount) + (nodeCount * (long)nodeBufferSize), ownsSharedMemory) { if (ownsSharedMemory && nodeCount < 2) { throw new ArgumentOutOfRangeException(nameof(nodeCount), nodeCount, RS.NodeCountRequireGeTwo); } #if DEBUG && NETFX else if (!ownsSharedMemory && (nodeCount != 0 || nodeBufferSize > 0)) { System.Diagnostics.Debug.Write("Node count and nodeBufferSize are ignored when opening an existing shared memory circular buffer.", "Warning"); } #endif if (IsOwnerOfSharedMemory) { NodeCount = nodeCount; NodeBufferSize = nodeBufferSize; } }
/// <summary> /// Returns a copy of the shared memory header. /// </summary> public NodeHeader ReadNodeHeader() { return(Polyfill.GetMarshalPtrToStructure <NodeHeader>(new IntPtr(_nodeHeader))); }
/// <summary> /// Creates a new or opens an existing shared memory buffer with the name of <see cref="Name"/> depending on the value of <see cref="IsOwnerOfSharedMemory"/>. /// </summary> /// <exception cref="System.IO.IOException">Trying to create a new shared memory buffer with a duplicate name as buffer owner.</exception> /// <exception cref="System.IO.FileNotFoundException">Trying to open a new shared memory buffer that does not exist as a consumer of existing buffer.</exception> /// <exception cref="System.ArgumentOutOfRangeException">Trying to create a new shared memory buffer with a size larger than the logical addressable space.</exception> /// <returns>`true` if the memory was successfully mapped. Otherwise, `false`.</returns> /// <remarks> /// If <see cref="IsOwnerOfSharedMemory"/> is `true`, the shared memory buffer will be created. Opening will fail in this case if the shared memory already /// exists. Otherwise, if <see cref="IsOwnerOfSharedMemory"/> is `false`, the shared memory buffer will be opened, which will fail if it doesn't already exist. /// </remarks> protected bool Open() { Close(); try { // Attempts to create or open the shared memory with a name of this.Name if (IsOwnerOfSharedMemory) { // Create a new shared memory mapping Mmf = MemoryMappedFile.CreateNew(Name, SharedMemorySize); // Create a view to the entire region of the shared memory View = Mmf.CreateViewAccessor(0, SharedMemorySize, MemoryMappedFileAccess.ReadWrite); View.SafeMemoryMappedViewHandle.AcquirePointer(ref ViewPtr); Header = (SharedBufferHeader *)(ViewPtr + HeaderOffset); BufferStartPtr = ViewPtr + BufferOffset; // Initialise the header InitializeHeader(); } else { // Open an existing shared memory mapping Mmf = MemoryMappedFile.OpenExisting(Name); // Retrieve the header from the shared memory in order to initialise the correct size using (var headerView = Mmf.CreateViewAccessor(0, HeaderOffset + Polyfill.GetMarshalSizeOf <SharedBufferHeader>(), MemoryMappedFileAccess.Read)) { byte *headerPtr = null; headerView.SafeMemoryMappedViewHandle.AcquirePointer(ref headerPtr); var header = (SharedBufferHeader *)(headerPtr + HeaderOffset); BufferSize = header->SharedMemorySize - Polyfill.GetMarshalSizeOf <SharedBufferHeader>(); headerView.SafeMemoryMappedViewHandle.ReleasePointer(); } // Create a view to the entire region of the shared memory View = Mmf.CreateViewAccessor(0, SharedMemorySize, MemoryMappedFileAccess.ReadWrite); View.SafeMemoryMappedViewHandle.AcquirePointer(ref ViewPtr); Header = (SharedBufferHeader *)(ViewPtr + HeaderOffset); BufferStartPtr = ViewPtr + HeaderOffset + Polyfill.GetMarshalSizeOf <SharedBufferHeader>(); } } catch { Close(); throw; } // Complete any additional open logic try { if (!DoOpen()) { Close(); return(false); } else { return(true); } } catch { Close(); throw; } }