예제 #1
0
        /// <summary>
        /// Reads the next available node for reading into the specified struct array
        /// </summary>
        /// <typeparam name="T">The structure type to be read</typeparam>
        /// <param name="buffer">Reference to the buffer</param>
        /// <param name="timeout">The maximum number of milliseconds to wait for a node to become available for reading (default 1000ms)</param>
        /// <returns>The number of bytes read</returns>
        /// <remarks>The maximum number of bytes that can be read is the minimum of the length of <paramref name="buffer"/> multiplied by <code>Marshal.SizeOf(typeof(T))</code> and <see cref="NodeBufferSize"/>.</remarks>
        public virtual int Read <T>(T[] buffer, int timeout = 1000)
            where T : struct
        {
            Node *node = GetNodeForReading(timeout);

            if (node == null)
            {
                return(0);
            }

            // Copy the data using the FastStructure class (much faster than the MemoryMappedViewAccessor ReadArray<T> method)
            int amount = Math.Min(buffer.Length, NodeBufferSize / FastStructure.SizeOf <T>());

            base.ReadArray <T>(buffer, node->Offset, 0, amount);

            // Return the node for further writing
            ReturnNode(node);

            return(amount);
        }
예제 #2
0
        /// <summary>
        /// Writes the struct array buffer to the next available node for writing
        /// </summary>
        /// <param name="buffer">Reference to the buffer to write</param>
        /// <param name="timeout">The maximum number of milliseconds to wait for a node to become available for writing (default 1000ms)</param>
        /// <returns>The number of bytes written</returns>
        /// <remarks>The maximum number of bytes that can be written is the minimum of the length of <paramref name="buffer"/> multiplied by <code>Marshal.SizeOf(typeof(T))</code> and <see cref="NodeBufferSize"/>.</remarks>
        public virtual int Write <T>(T[] buffer, int timeout = 1000)
            where T : struct
        {
            // Grab a node for writing
            Node *node = GetNodeForWriting(timeout);

            if (node == null)
            {
                return(0);
            }

            // Write the data using the FastStructure class (much faster than the MemoryMappedViewAccessor WriteArray<T> method)
            int amount = Math.Min(buffer.Length, NodeBufferSize / FastStructure.SizeOf <T>());

            base.WriteArray <T>(node->Offset, buffer, 0, amount);

            // Writing is complete, make node readable
            PostNode(node);

            return(amount);
        }
예제 #3
0
        /// <summary>
        /// Writes the structure array buffer to the next available node for writing
        /// </summary>
        /// <param name="source">Reference to the buffer to write</param>
        /// <param name="startIndex">The index within the buffer to start writing from</param>
        /// <param name="timeout">The maximum number of milliseconds to wait for a node to become available for writing (default 1000ms)</param>
        /// <returns>The number of elements written</returns>
        /// <remarks>The maximum number of elements that can be written is the minimum of the length of <paramref name="source"/> subtracted by <paramref name="startIndex"/> and <see cref="NodeBufferSize"/> divided by <code>FastStructure.SizeOf&gt;T&lt;()</code>.</remarks>
        public virtual int Write <T>(T[] source, int startIndex = 0)
            where T : struct
        {
            // Grab a node for writing
            Node *node = GetNodeForWriting();

            if (node == null)
            {
                return(0);
            }

            // Write the data using the FastStructure class (much faster than the MemoryMappedViewAccessor WriteArray<T> method)
            int count = Math.Min(source.Length - startIndex, NodeBufferSize / FastStructure.SizeOf <T>());

            base.WriteArray <T>(source, startIndex, count, node->Offset);
            node->AmountWritten = count * FastStructure.SizeOf <T>();

            // Writing is complete, make node readable
            PostNode(node);

            return(count);
        }
예제 #4
0
        /// <summary>
        /// Reads the next available node for reading into the specified structure array
        /// </summary>
        /// <typeparam name="T">The structure type to be read</typeparam>
        /// <param name="destination">Reference to the buffer</param>
        /// <param name="startIndex">The index within the destination to start writing to.</param>
        /// <param name="timeout">The maximum number of milliseconds to wait for a node to become available for reading (default 1000ms)</param>
        /// <returns>The number of elements read into destination</returns>
        /// <remarks>The maximum number of elements that can be read is the minimum of the length of <paramref name="destination"/> subtracted by <paramref name="startIndex"/> and <see cref="Node.AmountWritten"/> divided by <code>FastStructure.SizeOf&gt;T&lt;()</code>.</remarks>
        public virtual int Read <T>(T[] destination, int startIndex = 0, int timeout = 1000)
            where T : struct
        {
            Node *node = GetNodeForReading(timeout);

            if (node == null)
            {
                return(0);
            }

            // Copy the data using the FastStructure class (much faster than the MemoryMappedViewAccessor ReadArray<T> method)
            int count = Math.Min(destination.Length - startIndex, node->AmountWritten / FastStructure.SizeOf <T>());

            base.ReadArray <T>(destination, startIndex, count, node->Offset);

            // Return the node for further writing
            ReturnNode(node);

            return(count);
        }
예제 #5
0
        /// <summary>
        /// Construct a new RpcBuffer
        /// </summary>
        /// <param name="name">The unique channel name. This is the name to be shared between the master/slave pair. Each pair must have a unique value.</param>
        /// <param name="bufferCapacity">Master only: Maximum buffer capacity. Messages will be split into packets that fit this capacity (including a packet header of 64-bytes). The slave will use the same size as defined by the master</param>
        /// <param name="protocolVersion">ProtocolVersion.V1 = 64-byte header for each packet</param>
        /// <param name="bufferNodeCount">Master only: The number of nodes in the underlying circular buffers, each with a size of <paramref name="bufferCapacity"/></param>
        public RpcBuffer(string name, int bufferCapacity = 50000, RpcProtocol protocolVersion = RpcProtocol.V1, int bufferNodeCount = 10)
        {
            if (bufferCapacity < 256) // min 256 bytes
            {
                throw new ArgumentOutOfRangeException(nameof(bufferCapacity), "cannot be less than 256 bytes");
            }

            if (bufferCapacity > 1024 * 1024) // max 1MB
            {
                throw new ArgumentOutOfRangeException(nameof(bufferCapacity), "cannot be larger than 1MB");
            }

            Statistics = new RpcStatistics();

            masterMutex = new Mutex(true, name + "SharedMemory_MasterMutex", out bool createdNew);

            if (createdNew && masterMutex.WaitOne(500))
            {
                instanceType = InstanceType.Master;
            }
            else
            {
                instanceType = InstanceType.Slave;
                if (masterMutex != null)
                {
                    masterMutex.Close();
                    masterMutex.Dispose();
                    masterMutex = null;
                }
            }

            switch (protocolVersion)
            {
            case RpcProtocol.V1:
                this.protocolVersion = protocolVersion;
                protocolLength       = FastStructure.SizeOf <RpcProtocolHeaderV1>();
                Statistics.ProtocolOverheadPerPacket = protocolLength;
                break;
            }

            this.bufferCapacity  = bufferCapacity;
            this.bufferNodeCount = bufferNodeCount;
            if (instanceType == InstanceType.Master)
            {
                WriteBuffer = new CircularBuffer(name + "_Slave_SharedMemory_MMF", bufferNodeCount, this.bufferCapacity);
                ReadBuffer  = new CircularBuffer(name + "_Master_SharedMemory_MMF", bufferNodeCount, this.bufferCapacity);
            }
            else
            {
                ReadBuffer           = new CircularBuffer(name + "_Slave_SharedMemory_MMF");
                WriteBuffer          = new CircularBuffer(name + "_Master_SharedMemory_MMF");
                this.bufferCapacity  = ReadBuffer.NodeBufferSize;
                this.bufferNodeCount = ReadBuffer.NodeCount;
            }

            this.msgBufferLength = Convert.ToInt32(this.bufferCapacity) - protocolLength;

            Task.Run(() =>
            {
                switch (protocolVersion)
                {
                case RpcProtocol.V1:
                    ReadThreadV1();
                    break;
                }
            });
        }