首页 > 其他分享 >Golang:无锁队列实现

Golang:无锁队列实现

时间:2024-03-24 15:44:52浏览次数:26  
标签:head 无锁 队列 unsafe next Golang tail atomic Pointer

无锁队列实现

无锁队列实现

参考论文

适用场景

并发条件下, 需要使用到队列的情况, 都可以使用无锁队列

技术要点

  1. 使用atomic.loadpointer 来实现实时的指针相等判断
  2. 使用CAS来替代同步状态下的 p = p.next
  3. 额外判断tail是不是正确的tail, 并且不断地尝试推后他

示例代码

package djj_worker_pool

import (
    "sync/atomic"
    "unsafe"
)

type QueueNode struct {
    value any
    next  unsafe.Pointer
}

func newNode(v any) *QueueNode {
    return &QueueNode{
        value: v,
        next:  nil,
    }
}

type Queue struct {
    head unsafe.Pointer
    tail unsafe.Pointer
}

func (q *Queue) Enqueue(v any) {
    node := newNode(v)
    for {
        tail := load(&q.tail)
        next := tail.next
        if tail == load(&q.tail) {
            if next == nil {
                // add to tail
                if atomic.CompareAndSwapPointer(&tail.next, next, unsafe.Pointer(node)) {
                    // switch tail to node
                    atomic.CompareAndSwapPointer(&q.tail, unsafe.Pointer(tail), unsafe.Pointer(node))
                    break
                }
            } else {
                // get wrong tail node
                // tail = tail.next
                // if can not , reload tail in next loop
                atomic.CompareAndSwapPointer(&q.tail, unsafe.Pointer(tail), next)
            }
        }
    }
}

func (q *Queue) Dequeue() (res any) {
    for {
        head := load(&q.head)
        tail := load(&q.tail)
        next := head.next

        if head == load(&q.head) {
            if head == tail {
                if next == nil {
                    return nil // has no value
                }
                atomic.CompareAndSwapPointer(&q.tail, unsafe.Pointer(tail), next)
            } else {
                v := load(&next).value
                if atomic.CompareAndSwapPointer(&q.head, unsafe.Pointer(head), next) {
                    return v
                }
            }
        }
    }
}

func NewQueue() *Queue {
    node := unsafe.Pointer(&QueueNode{})
    return &Queue{
        head: node,
        tail: node,
    }
}

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

参考文档

https://www.cs.rochester.edu/u/scott/papers/1996_PODC_queues.pdf

https://colobu.com/2020/08/14/lock-free-queue-in-go/

标签:head,无锁,队列,unsafe,next,Golang,tail,atomic,Pointer
From: https://www.cnblogs.com/pDJJq/p/18092510/no-lock-queue-implementation-12u9ni

相关文章

  • Golang: 通过chan来实现并发访问控制
    通过chan来实现并发访问控制通过chan来实现并发访问控制背景介绍这是在阅读grom的源码时,他的schema的初始化方式,给我留下来很深刻的印象,本文将通过channel的一些使用来实现实例的并发访问技术要点如果chan为空时,尝试读可以成功,获得的结果为空示例代码packagemai......
  • 无锁、偏向锁、轻量级锁和重量级锁
    在JDK1.6版本之前,所有的Java内置锁都是重量级锁。重量级锁会造成CPU在用户态和核心态之间频繁切换,所以代价高、效率低。JDK1.6版本为了减少获得锁和释放锁所带来的性能消耗,引入了偏向锁和轻量级锁的实现。所以,在JDK1.6版本中内置锁一共有4种状态:无......
  • Python数据结构实验 队列的实现
    一、实验目的1.掌握用Python定义队列的顺序存储结构和链式存储结构,以便在实际背景下灵活运用;2.掌握队列的特点,即先进先出的原则;3.掌握队列的基本操作实现方法。二、实验环境1.Windows操作系统的计算机2.Python3.7环境平台和PyCharm编辑器三、实验说明 1.实现队列的顺序存......
  • Golang: 探究sync.map的实现
    Golang:探究sync.map的实现背景探究下载并发模式下,sync.map的实现,以及该实现方式可能引入的问题链接Github基本使用packagemainimport"sync"funcmain(){ m:=sync.Map{} m.Load("key") m.Store("key","value") m.LoadOrStore("key",&q......
  • Golang标准库fmt深入解析与应用技巧
    Golang标准库fmt深入解析与应用技巧前言fmt包的基本使用打印与格式化输出函数Print系列函数格式化字符串格式化输入函数小结字符串格式化基本类型的格式化输出自定义类型的格式化输出控制格式化输出的宽度和精度小结错误处理与fmt使用fmt.Errorf生成错误信息fmt包与错......
  • golang interface转int
    varres[]orm.Params//切片map,value为interface;//获取当前时间now:=time.Now()//获取30天前的时间thirtyDaysAgo:=now.AddDate(0,0,-30)//将时间转换为时间戳timestamp:=thirtyDaysAgo.Unix()sql:=fmt.Sprint("SELECTcount(*)asnum,media.idasarticle_id,m......
  • Golang: Redislock源码分析
    Golang:Redislock源码分析源码https://github.com/bsm/redislock实现Lua脚本obtain.lua--obtain.lua:arguments=>[value,tokenLen,ttl]--Obtain.luatrytosetprovidedkeys'swithvalueandttliftheydonotexists.--Keyscanbeoverrideniftheyal......
  • 游戏开发:移植golang共享库 for lua
    一些奇奇怪怪的尝试:)随笔记录下将golang模块导出为共享库供lua使用(一般用于功能模块适配和迁移),这里给出一个借助c语言实现中间层通信的方案(不要问我为什么不使用ffi)。假设使用go实现底层模块core,export相关API(如下例的G_Signature)供外部使用,这里是被C层使用。那么需要将go模块编......
  • 【消息队列开发】 实现 VirtualHostTests 类——测试虚拟主机操作
    文章目录......
  • 【Golang星辰图】实现弹性微服务架构:使用go-micro和go-kit构建可扩展的网络应用
    构建高效网络应用:探索分布式系统和微服务的利器前言在当今的互联网时代,构建可扩展且可靠的网络应用变得越来越重要。分布式系统和微服务架构成为了解决大规模应用程序开发和管理的有效方法。本文将介绍一些用于构建分布式系统和微服务的关键工具和库,例如go-rpc、go-micro......