Skip to content

Instantly share code, notes, and snippets.

@ocoanet
Created December 19, 2016 19:53
Show Gist options
  • Star 0 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save ocoanet/22b946da00d16b68ab7489e811910951 to your computer and use it in GitHub Desktop.
Save ocoanet/22b946da00d16b68ab7489e811910951 to your computer and use it in GitHub Desktop.
using System.Runtime.InteropServices;
using System.Threading;
namespace Foo
{
/// <summary>
/// Naive SPMC queue.
/// </summary>
public class NaiveQueue
{
private readonly int[] _items;
private Fields _fields;
public NaiveQueue(int capacity)
{
_items = new int[capacity];
}
public bool TryPush(int value)
{
return TryEnqueue(value);
}
public bool TryEnqueue(int value)
{
var readPosition = Volatile.Read(ref _fields.Read.Position);
var nextWritePosition = (_fields.WritePosition + 1) % _items.Length;
if (nextWritePosition == readPosition)
return false;
_items[_fields.WritePosition] = value;
_fields.WritePosition = nextWritePosition;
return true;
}
public bool TryPop(out int value)
{
return TryDequeue(out value);
}
public bool TryDequeue(out int value)
{
var positionAndVersion = new VersionAndPosition();
while (true)
{
var originalVersionAndPosition = Volatile.Read(ref _fields.Read.Value);
positionAndVersion.Value = originalVersionAndPosition;
var writePosition = Volatile.Read(ref _fields.WritePosition);
if (positionAndVersion.Position == writePosition)
{
value = 0;
return false;
}
var readValue = _items[positionAndVersion.Position];
positionAndVersion.Position = (positionAndVersion.Position + 1) % _items.Length;
positionAndVersion.Version++;
if (Interlocked.CompareExchange(ref _fields.Read.Value, positionAndVersion.Value, originalVersionAndPosition) == originalVersionAndPosition)
{
value = readValue;
return true;
}
}
}
[StructLayout(LayoutKind.Explicit, Size = 4 + 64 + 8)]
private struct Fields
{
[FieldOffset(0)]
public int WritePosition;
[FieldOffset(4 + 64)]
public VersionAndPosition Read;
}
[StructLayout(LayoutKind.Explicit, Size = 8)]
private struct VersionAndPosition
{
[FieldOffset(0)]
public int Version;
[FieldOffset(4)]
public int Position;
[FieldOffset(0)]
public long Value;
}
}
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment