无锁队列中的这些行是不必要的吗?

发布于 2024-10-26 04:32:01 字数 1304 浏览 1 评论 0原文

以下是使用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 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(3

一梦等七年七年为一梦 2024-11-02 04:32:02

是的,在 Java 中,考虑到它有垃圾收集功能,这些 if 只具有优化的真正价值,而且它有点大:与仅从内存中读取相比,CAS 非常昂贵,因此请确保该值在同时,从而减少后续 CAS 失败的机会,有助于减少 CAS 重试次数,从而提高性能。

您还可以移动第一个==最后一个&& tail-update 检查 head.CAS 内部,作为进一步的优化:只有当 head 更新时,tail 才会落后,因此只有 CAS 成功时才进行检查才有意义。您也可以将 tail.get 移动到那里,因为您在其他地方不需要它。下面的示例代码。希望这有帮助!

public T deq() throws EmptyException {
while(true) {
    Node first = head.get();
    Node next = first.next.get();

    if (first != head.get())
        continue;

    if (next == null) {
        throw new EmptyException();
    }

    T value = next.value;

    if (head.compareAndSet(first, next)) {
        Node last = tail.get();

        if (first == last) {
            tail.compareAndSet(last, next);
        }

        return value;
    }
}

}

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!

public T deq() throws EmptyException {
while(true) {
    Node first = head.get();
    Node next = first.next.get();

    if (first != head.get())
        continue;

    if (next == null) {
        throw new EmptyException();
    }

    T value = next.value;

    if (head.compareAndSet(first, next)) {
        Node last = tail.get();

        if (first == last) {
            tail.compareAndSet(last, next);
        }

        return value;
    }
}

}

浅唱ヾ落雨殇 2024-11-02 04:32:02

它们不是必需的,但出于性能原因使用,请注意检查是在不使用原子操作的情况下进行的。

来自 MSDN 的示例成本:

  • MemoryBarrier 是测量为 20-90 个周期。
  • InterlockedIncrement 测量为 36-90 个周期。
  • 获取或释放关键部分被测量为需要 40-100 个周期。
  • 测量获取或释放互斥体需要大约 750-2500 个周期。

此特定技术的参考:

[鲁道夫与Segall 84]鲁道夫,L.和
Segall, Z. 动态去中心化
MIMD 并行缓存方案
处理器。 Invù roceedingsof
theíúvúth 年度研讨会
计算机体系结构,页面
340i›347, 1984.

They are not necessary but used for performance reasons, notice the check occurs without using an atomic operation.

Example costs from MSDN:

  • MemoryBarrier was measured as taking 20-90 cycles.
  • InterlockedIncrement was measured as taking 36-90 cycles.
  • Acquiring or releasing a critical section was measured as taking 40-100 cycles.
  • Acquiring or releasing a mutex was measured as taking about 750-2500 cycles.

Reference for this particular technique:

[Rudolph & Segall 84] Rudolph, L. and
Segall, Z. Dy-namic Decentralized
Cache Schemes forMIMD Parallel
Processors. Invù roceedingsof
theíúvúth Annual Symposium on
Com-puter Architecture, pages
340i›347, 1984.

纵性 2024-11-02 04:32:02

它是非阻塞链表算法。
详细描述在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)

~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文