I was reading the source code of ConcurrentQueue, here are some code:
/// <summary>
/// Store the position of the current head and tail positions.
/// </summary>
/// <param name="head">return the head segment</param>
/// <param name="tail">return the tail segment</param>
/// <param name="headLow">return the head offset, value range [0, SEGMENT_SIZE]</param>
/// <param name="tailHigh">return the tail offset, value range [-1, SEGMENT_SIZE-1]</param>
private void GetHeadTailPositions(out Segment head, out Segment tail,
out int headLow, out int tailHigh)
{
head = m_head;
tail = m_tail;
headLow = head.Low;
tailHigh = tail.High;
SpinWait spin = new SpinWait();
//we loop until the observed values are stable and sensible.
//This ensures that any update order by other methods can be tolerated.
while (
//if head and tail changed, retry
head != m_head || tail != m_tail
//if low and high pointers, retry
|| headLow != head.Low || tailHigh != tail.High
//if head jumps ahead of tail because of concurrent grow and dequeue, retry
|| head.m_index > tail.m_index)
{
spin.SpinOnce();
head = m_head;
tail = m_tail;
headLow = head.Low;
tailHigh = tail.High;
}
}
GetHeadTailPositions() may want to get 4 variables at a particular time, however, there are 4 compare in the 'where' loop, think about the below sequence:
while (
// 1. head equals m_head
head != m_head
// 2. m_head was changed while other variables were unchanged
|| tail != m_tail || headLow != head.Low || tailHigh != tail.High || head.m_index > tail.m_index)
{
// ...
}
then we get a unstable version of these variables. Is this method stable? How to get a stable version of mutiple values at a particular time without lock?