今天早上,当我遇到一个我不理解的C#代码示例时,我正在阅读源代码:
public bool Dequeue(out T value)
{
Node head;
Node tail;
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...
}
}
我遇到的问题是包含Object.ReferenceEquals()
的问题。
如果我理解得很好,源代码作者想要比较this.head
和head
,但在上面的行中,他只是写了head = this.head
。
主要来自C++
背景,这句话对我来说毫无意义。此外,在某些情况下,似乎Object.ReferenceEquals()
行会抛出一个System.NullReferenceException
所以它确实会有所作为,我无法弄清楚是什么。
你能帮助我理解这条线路的作用以及可能的原因吗?
如果你需要这个,这里是Node
类定义(我猜它是一个“模板”类,不确定C#的措辞):
private class Node
{
public T Value;
public Node Next;
public Node(T value)
{
this.Value = value;
}
}
谢谢。
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);
}
}
}
}
答案 0 :(得分:2)
看起来像一个链表。 Dequeue看起来像一个递归函数。 因此,“Next”会对节点的“head”部分执行某些操作,或者它并行运行,并且在继续操作之前,他会尝试检查内容是否仍然存在。最后一部分操作不正确,因为您在进入临界区时应该使用信号量,否则您将遇到竞争条件并且迟早会失败。
答案 1 :(得分:1)
如果this.head
和this.tail
是公开的,则可以在循环运行时更改它们。 Object.ReferenceEquals
检查它们是否与执行方法时相同。
如果没有全班/上下文,很难给出更完整的答案。
答案 2 :(得分:1)
他刚写了
head = this.head
这是作业,并且与比较它们有关。请注意,这是关于字段head
和本地var this.head
。
if(Object.ReferenceEquals(this.head,head))
此处作者希望比较this.head
和head
,同时确保相等性基于其引用(地址),而不是==
和{{{} {{}} 1}}
我假设在循环内部正在更改局部变量Equals()
,这使它成为一个有争议的命名。
答案 3 :(得分:1)
ReferenceEquals是一个函数,用于确保对象的两个实例是完全相同的对象,而不仅仅是两个具有相同值的对象。可以在此处找到文档(http://msdn.microsoft.com/en-us/library/system.object.referenceequals.aspx)。至于该语句的目标,如果这个代码在多线程上下文中执行,他可能会试图确保没有人因为他做了(非常危险),或者担心有人传入值类型(危险) ,但更好的检查方法)。
编辑:随着更多代码发布,它看起来像第一件事。当有多个线程时,他正在使用ReferenceEquals来尝试捕捉他的竞争条件(如果它不是多线程的,他就不会打扰InterlockedExchange)。代码似乎基本上是在尝试执行操作,并且,如果有人在中途改变了马匹,只需再次尝试(而(真实))。使用关键部分或信号量来确保没有人修改你的价值观,而不是简单地希望你能检查它们是否有所改变,这可能更为优雅。原因是 AFTER IF,但 BEFORE InterlockedExchange,有人可能会修改您的值,这会引入错误。
答案 4 :(得分:1)
Interlocked.CompareExchange
方法用于执行线程安全比较和替换 - 这意味着此方法应该能够处理外部线程修改队列的情况。
if
语句正在尝试处理列表已被其他线程修改的情况