Code understanding issues
I was reading a source code this morning when I came across a C# code sample that I don't understand:
public bool Dequeue(out T value)
{
Node head;
Node tai开发者_如何学编程l;
Node next;
while (true)
{
// read head
head = this.head;
tail = this.tail;
next = head.Next;
// Are head, tail, and next consistent?
if (Object.ReferenceEquals(this.head, head))
{
// Source code continues here...
}
// And here...
}
}
The line I've got an issue with it the one which contains Object.ReferenceEquals()
.
If I understand well, the source code author wants to compare this.head
and head
but on the lines above, he just wrote head = this.head
.
Coming mainly from a C++
background, this statement makes no sense to me. Moreover, under some circunstances, it seems that the Object.ReferenceEquals()
line throws a System.NullReferenceException
so it certainly does something, I just can't figure out what.
Can you help me understanding what this line does and possibly why ?
In case you need this, here is the Node
class definition (I guess it is a "template" class, not sure of the wording for C#):
private class Node
{
public T Value;
public Node Next;
public Node(T value)
{
this.Value = value;
}
}
Thank you.
Edit: The rest of the method, for those who asked
public void Enqueue(T value)
{
// Allocate a new node from the free list
Node valueNode = new Node(value);
while (true)
{
Node tail = this.tail;
Node next = tail.Next;
// are tail and next consistent
if (Object.ReferenceEquals(tail, this.tail))
{
// was tail pointing to the last node?
if (Object.ReferenceEquals(next, null))
{
if (Object.ReferenceEquals(
Interlocked.CompareExchange(ref tail.Next, valueNode, next),
next
)
)
{
Interlocked.CompareExchange(ref this.tail, valueNode, tail);
break;
}
}
else // tail was not pointing to last node
{
// try to swing Tail to the next node
Interlocked.CompareExchange<Node>(ref this.tail, next, tail);
}
}
}
}
Looks like a linked list. Dequeue looks like a recursive function. So either "Next" does something with the "head" part of a node or it's running in parallel, and he is trying to check if stuff is still where it is, before proceeding. The last part is done incorrectly since you should be using a semaphore when entering a critical section, otherwise you are running into race conditions and it will fail sooner or later.
he just wrote
head = this.head
Which is an assignment and has noting to do with comparing them. Note that this is about a field head
and a local var this.head
.
if (Object.ReferenceEquals(this.head, head))
Here the author wants to compare this.head
and head
while making sure the equality is based on their references (addresses), not on any (possible) overloading of ==
and Equals()
I assume that the local var head
is being changed inside the loop, which makes it a disputable naming.
If this.head
and this.tail
is public, they can be changed while the loop is running. Object.ReferenceEquals
checks if they are the same as when the method was executed.
It's hard to give a more complete answer without the whole class / context.
The Interlocked.CompareExchange
method is used to perform thread safe comparison and replacement - meaning this method should be able to handle cases where the queue is modified by external threads.
The if
statement is trying to handle cases where the list has been modified by other threads
ReferenceEquals is a function that is used to make sure that two instances of an object are the exact same object, rather than just two objects which have identical values. Documentation can be found here (http://msdn.microsoft.com/en-us/library/system.object.referenceequals.aspx). As to the goal of that statement, if this code is executing in a multithreaded context, he could be trying to ensure that no one has messed with head since he did (very dangerous), or worried that someone passed in a value type (dangerous, but better ways to check).
EDIT: With the further code posted, it looks like the first thing. He's using ReferenceEquals to try to catch his race conditions when there are multiple threads (if it wasn't multi-threaded, he would not bother with InterlockedExchange). The code seems to be basically trying to perform an operation, and, if someone has changed horses on it in mid stream, simply trying again (while (true)). It'd probably be more elegant to use a critical section or a semaphore to ensure that nobody DOES modify your values, rather than simply hoping you can check if they have. The reason for that is that AFTER the IF, but BEFORE the InterlockedExchange, someone may modify your values, which introduces a bug.
精彩评论