Beispiel #1
0
        /// <summary>
        /// Allows writing thread to write next message.
        /// Can be called simultaneously from multiple threads.
        /// </summary>
        /// <returns>
        /// False if there was not enough room in the inbox to write
        /// the message.
        /// </returns>
        public bool TryWrite(Span <byte> toWrite)
        {
            if (!ClientServerMessage.TryGetLength(toWrite, out var messageSize))
            {
                throw new ArgumentException("Message shorter than 4 bytes.");
            }

            // Verify the validity of the given message length.
            if (toWrite.Length != messageSize)
            {
                throw new ArgumentOutOfRangeException(
                          $"Message of size {messageSize} in span of size {toWrite.Length}.");
            }

            if (toWrite.Length > ClientServerMessage.MaxSizeInBytes)
            {
                throw new ArgumentOutOfRangeException(
                          $"Message size {messageSize} exceeds {ClientServerMessage.MaxSizeInBytes}.");
            }

            // Reserve a space to write by moving `_write` forward by the expected
            // length. `write` remembers the start of the reserved space.

            long write;

            do
            {
                write = _write;
                if (_sizeInBytes - (int)(write - _start) < toWrite.Length)
                {
                    return(false);
                }
            } while (write != Interlocked.CompareExchange(ref _write, write + toWrite.Length, write));

            try
            {
                // Write to the reserved space

                var start = write % _sizeInBytes;
                for (var i = 0; i < toWrite.Length; ++i)
                {
                    _inbox[start + i] = toWrite[i];
                }

                return(true);
            }
            finally
            {
                // Wait until we can move `_end` forward (previously pending writes must finish
                // first, or we'll expose readers to incomplete messages).

                while (_end <= write)
                {
                    Interlocked.CompareExchange(ref _end, write + toWrite.Length, write);
                }
            }
        }
Beispiel #2
0
        /// <summary>
        /// Read the next message of the Inbox
        /// without erasing the read data.
        /// </summary>
        public Span <byte> Peek()
        {
            int startMod = (int)(_start % _sizeInBytes);

            if (_start < _end)
            {
                if (ClientServerMessage.TryGetLength(new Span <byte>(_inbox).Slice(startMod), out var bufferSize))
                {
                    return(new Span <byte>(_inbox, startMod, bufferSize));
                }
            }

            return(new Span <byte>(_inbox, startMod, 0));
        }