Following up on the previous post we are now going to modify the LocklessQueue<T> to allocate a class for an array of items rather than just a single item. Most of this work will be in the Item class itself with a few changes to the Enqueue method. Again we have to ensure that both the variables are written to by only one of the threads. Time for more code:
class LocklessQueue<T>
{
class Item
{
public Item Next;
int _pos, _count;
readonly T[] _values;
public Item(int capacity)
{
_pos = _count = 0;
_values = new T[capacity];
Next = null;
}
public bool IsValid { get { return _pos < _count; } }
public bool PutValue(T value)
{
if (_count < _values.Length)
{
_values[_count++] = value;
return true;
}
return false;
}
public T TakeValue()
{
int ix = _pos++;
T value = _values[ix];
_values[ix] = default(T);
return value;
}
}
readonly int _allocSize;
Item _first;
Item _last;
public LocklessQueue(int allocSize)
{
_allocSize = Math.Max(1, allocSize);
_first = _last = new Item(_allocSize);
}
public bool IsEmpty
{
get
{
while (!_first.IsValid && _first.Next != null)
_first = _first.Next;
return false == _first.IsValid;
}
}
public void Enqueue(T value)
{
if (!_last.PutValue(value))
{
Item i = new Item(_allocSize);
i.PutValue(value);
_last.Next = i;
_last = i;
}
}
public T Dequeue()
{
while (!_first.IsValid && _first.Next != null)
_first = _first.Next;
if (!_first.IsValid)
throw new InvalidOperationException();//queue is empty
return _first.TakeValue();
}
}
Trackbacks