无锁队列中的这些行是不必要的吗?
以下是使用compareAndSet(Java中)的无锁队列的一些代码:
public void enq(T value) {
Node newNode = new Node(value);
while(true) {
Node last = tail.get();
Node next = last.next.get();
if(last != tail.get())
continue; //???
if (next != null) { //improve tail
tail.compareAndSet(last, next);
continue;
}
if (last.next.compareAndSet(null, newNode)) { //update last node
tail.compareAndSet(last, newNode); //update tail
return;
}
}
}
public T deq() throws EmptyException {
while(true) {
Node first = head.get();
Node last = tail.get();
Node next = first.next.get();
if(first != head.get())
continue; //???
if(first == last) {
if (next == null)
throw new EmptyException();
tail.compareAndSet(last, next);
continue;
}
T value = next.value;
if (head.compareAnsdSet(first, next)) {
return value;
}
}
}
(head和tail是队列的成员)
在deq和enq函数中,第一次检查对我来说似乎没有必要。 (评论里有“???”的) 我怀疑它只是为了某种优化。
我在这里错过了什么吗?这些检查会影响代码的正确性吗?
(该代码取自“多处理器编程的艺术”,尽管我确实重构了代码风格,以减少嵌套的 if 和 else,同时保持代码等效)
Here is some code from a lock-free queue using compareAndSet (in Java):
public void enq(T value) {
Node newNode = new Node(value);
while(true) {
Node last = tail.get();
Node next = last.next.get();
if(last != tail.get())
continue; //???
if (next != null) { //improve tail
tail.compareAndSet(last, next);
continue;
}
if (last.next.compareAndSet(null, newNode)) { //update last node
tail.compareAndSet(last, newNode); //update tail
return;
}
}
}
public T deq() throws EmptyException {
while(true) {
Node first = head.get();
Node last = tail.get();
Node next = first.next.get();
if(first != head.get())
continue; //???
if(first == last) {
if (next == null)
throw new EmptyException();
tail.compareAndSet(last, next);
continue;
}
T value = next.value;
if (head.compareAnsdSet(first, next)) {
return value;
}
}
}
(head and tail are the members of the queue)
In both the deq and enq function, the first check seems unnecessary to me. (The ones commented with "???")
I suspect it's there just for some kind of optimization.
Am I missing something here? Do these checks affect the correctness of the code?
(The code is taken from the "Art of Multi-processor Programming", though I did refactor the code style to have less nested ifs and elses, while keeping the code equivalent)
如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。
绑定邮箱获取回复消息
由于您还没有绑定你的真实邮箱,如果其他用户或者作者回复了您的评论,将不能在第一时间通知您!
发布评论
评论(3)
是的,在 Java 中,考虑到它有垃圾收集功能,这些 if 只具有优化的真正价值,而且它有点大:与仅从内存中读取相比,CAS 非常昂贵,因此请确保该值在同时,从而减少后续 CAS 失败的机会,有助于减少 CAS 重试次数,从而提高性能。
您还可以移动第一个==最后一个&& tail-update 检查 head.CAS 内部,作为进一步的优化:只有当 head 更新时,tail 才会落后,因此只有 CAS 成功时才进行检查才有意义。您也可以将 tail.get 移动到那里,因为您在其他地方不需要它。下面的示例代码。希望这有帮助!
}
Yeah, in Java, given that it has garbage collection, those ifs have only real value as optimization, and it's kinda a big one: CAS is incredibly expensive compared to just a read from memory, so making sure the value hasn't changed in the meantime, and thus decreasing the chance of failing on the subsequent CAS, helps reduce the number of CAS-retries, which helps performance.
You can also move the first == last && tail-update check to inside the head.CAS, as a further optimization: the tail can lag behind only if the head was updated, so checking that only if the CAS succeeded makes sense. You can also move tail.get there then, as you don't need it anywhere else. Example code below. Hope this helps!
}
它们不是必需的,但出于性能原因使用,请注意检查是在不使用原子操作的情况下进行的。
来自 MSDN 的示例成本:
此特定技术的参考:
They are not necessary but used for performance reasons, notice the check occurs without using an atomic operation.
Example costs from MSDN:
Reference for this particular technique:
它是非阻塞链表算法。
详细描述在JCP书中(15.4.2. A Nonblocking Linked List)
it's non-blocking linked list algorithm.
A detailed description is in the JCP book (15.4.2. A Nonblocking Linked List)