72 lines
1.7 KiB
C#
72 lines
1.7 KiB
C#
namespace JD.Collections.Lockless
|
|
{
|
|
/// <summary>
|
|
/// A simple lockless queue. Will ONLY work with ONE producer thread and ONE consumer thread.
|
|
/// </summary>
|
|
/// <remarks>
|
|
/// Inspired from http://www.ddj.com/architect/210604448?pgno=2 (Dr. Dobb's: Writing Lock-Free Code: A Corrected Queue)
|
|
/// </remarks>
|
|
public class OneProducerOneConsumerLocklessQueue<T>
|
|
{
|
|
#region Variables
|
|
|
|
private Node m_first; // for producer only
|
|
private volatile Node m_divider, m_last; // shared
|
|
|
|
#endregion
|
|
|
|
#region Constructor
|
|
|
|
public OneProducerOneConsumerLocklessQueue()
|
|
{
|
|
// add dummy separator
|
|
m_first = m_divider = m_last = new Node(default(T));
|
|
}
|
|
|
|
#endregion
|
|
|
|
#region Methods
|
|
|
|
public void Produce(T value)
|
|
{
|
|
m_last.Next = new Node(value); // add the new item
|
|
m_last = m_last.Next; // publish it
|
|
while (m_first != m_divider)
|
|
{
|
|
// trim unused nodes
|
|
m_first = m_first.Next;
|
|
}
|
|
}
|
|
|
|
public bool Consume(out T value)
|
|
{
|
|
if (m_divider != m_last)
|
|
{
|
|
// if queue is nonempty
|
|
value = m_divider.Next.Value; // copy it back
|
|
m_divider = m_divider.Next; // publish that we took it
|
|
return true;
|
|
}
|
|
|
|
value = default(T);
|
|
return false;
|
|
}
|
|
|
|
#endregion
|
|
|
|
#region Inner Types
|
|
|
|
private class Node
|
|
{
|
|
public readonly T Value;
|
|
public Node Next;
|
|
|
|
public Node(T value)
|
|
{
|
|
Value = value;
|
|
}
|
|
}
|
|
|
|
#endregion
|
|
}
|
|
}
|