go無鎖隊(duì)列

package queue

import (
    "sync/atomic"
    "unsafe"
)

// 無鎖隊(duì)列
type Queue struct {
    head, tail unsafe.Pointer
    size       int32
}

type Node struct {
    value any
    next  unsafe.Pointer
}

func (q *Queue) Enqueue(value any) {
    n := &Node{value: value}
retry:
    tail := load(&q.tail)
    next := load(&tail.next)
    if tail == load(&q.tail) {
        //如果next為空,則表示tail節(jié)點(diǎn)是隊(duì)列中的最后一個(gè)節(jié)點(diǎn),
        //代碼嘗試將新節(jié)點(diǎn)n鏈接到隊(duì)列的尾部,然后將tail指針向前移動(dòng)到新添加的節(jié)點(diǎn)
        if next == nil {
            if cas(&tail.next, next, n) {
                cas(&q.tail, tail, n)
                atomic.AddInt32(&q.size, 1)
                return
            }
        } else {
            //如果next不為空,表示tail節(jié)點(diǎn)并不是指向隊(duì)列中的最后一個(gè)節(jié)點(diǎn),此時(shí)代碼嘗試將tail指針向前移動(dòng)到下一個(gè)節(jié)點(diǎn)。
            cas(&q.tail, tail, next)
        }
    }
    goto retry
}

func (q *Queue) Dequeue() any {
retry:
    head := load(&q.head)
    tail := load(&q.tail)
    next := load(&head.next)
    if head == load(&q.head) {
        if head == tail {
            if next == nil {
                return nil
            }
            cas(&q.tail, tail, next)
        } else {
            //此行不能省略,在CAS之前讀取,否則會被另一個(gè)dequeue操作修改
            value := next.value
            if cas(&q.head, head, next) {
                atomic.AddInt32(&q.size, -1)
                return value
            }
        }
    }

    goto retry
}

func (q *Queue) IsEmpty() bool {
    return atomic.LoadInt32(&q.size) == 0
}

func load(p *unsafe.Pointer) *Node {
    return (*Node)(atomic.LoadPointer(p))
}

func cas(p *unsafe.Pointer, old, new *Node) bool {
    return atomic.CompareAndSwapPointer(p, unsafe.Pointer(old), unsafe.Pointer(new))
}

最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請聯(lián)系作者
【社區(qū)內(nèi)容提示】社區(qū)部分內(nèi)容疑似由AI輔助生成,瀏覽時(shí)請結(jié)合常識與多方信息審慎甄別。
平臺聲明:文章內(nèi)容(如有圖片或視頻亦包括在內(nèi))由作者上傳并發(fā)布,文章內(nèi)容僅代表作者本人觀點(diǎn),簡書系信息發(fā)布平臺,僅提供信息存儲服務(wù)。

友情鏈接更多精彩內(nèi)容