iis服务器助手广告广告
返回顶部
首页 > 资讯 > 后端开发 > GO >Golang自旋锁的相关介绍
  • 735
分享到

Golang自旋锁的相关介绍

2024-04-02 19:04:59 735人浏览 薄情痞子
摘要

目录自旋锁golang实现自旋锁可重入的自旋锁和不可重入的自旋锁自旋锁的其他变种1. TicketLock2. CLHLock3. MCSLock4. CLHLock 和 MCSLo

自旋锁

获取锁的线程一直处于活跃状态,但是并没有执行任何有效的任务,使用这种锁会造成busy-waiting。 它是为实现保护共享资源而提出的一种锁机制。其实,自旋锁与互斥锁比较类似,它们都是为了解决某项资源的互斥使用。无论是互斥锁,还是自旋锁,在任何时刻,最多只能由一个保持者,也就说,在任何时刻最多只能有一个执行单元获得锁。但是两者在调度机制上略有不同。对于互斥锁,如果资源已经被占用,资源申请者只能进入睡眠状态。但是自旋锁不会引起调用者睡眠,如果自旋锁已经被别的执行单元保持,调用者就一直循环在那里看是否该自旋锁的保持者已经释放了锁,“自旋”一词就是因此而得名。

Golang实现自旋锁

type spinLock uint32
func (sl *spinLock) Lock() {
    for !atomic.CompareAndSwapUint32((*uint32)(sl), 0, 1) {
        runtime.Gosched()
    }
}
func (sl *spinLock) Unlock() {
    atomic.StoreUint32((*uint32)(sl), 0)
}
func NewSpinLock() sync.Locker {
    var lock spinLock
    return &lock
}

可重入的自旋锁和不可重入的自旋锁

上面的代码,仔细分析一下就可以看出,它是不支持重入的,即当一个线程第一次已经获取到了该锁,在锁释放之前又一次重新获取该锁,第二次就不能成功获取到。由于不满足CAS,所以第二次获取会进入while循环等待,而如果是可重入锁,第二次也是应该能够成功获取到的。

而且,即使第二次能够成功获取,那么当第一次释放锁的时候,第二次获取到的锁也会被释放,而这是不合理的。

为了实现可重入锁,我们需要引入一个计数器,用来记录获取锁的线程数

type spinLock struct {
      owner int
      count  int
}
func (sl *spinLock) Lock() {
        me := GetGoroutineId()
        if spinLock .owner == me { // 如果当前线程已经获取到了锁,线程数增加一,然后返回
               sl.count++
               return
        }
        // 如果没获取到锁,则通过CAS自旋
    for !atomic.CompareAndSwapUint32((*uint32)(sl), 0, 1) {
        runtime.Gosched()
    }
}
func (sl *spinLock) Unlock() {
      if  rl.owner != GetGoroutineId() {
          panic("illegalMonitorStateError")
      }
      if sl.count >0  { // 如果大于0,表示当前线程多次获取了该锁,释放锁通过count减一来模拟
           sl.count--
       }else { // 如果count==0,可以将锁释放,这样就能保证获取锁的次数与释放锁的次数是一致的了。
           atomic.StoreUint32((*uint32)(sl), 0)
       }
}
func GetGoroutineId() int {
    defer func()  {
        if err := recover(); err != nil {
            fmt.Println("panic recover:panic info:%v", err)     }
    }()
    var buf [64]byte
    n := runtime.Stack(buf[:], false)
    idField := strings.Fields(strings.TrimPrefix(string(buf[:n]), "goroutine "))[0]
    id, err := strconv.Atoi(idField)
    if err != nil {
        panic(fmt.Sprintf("cannot get goroutine id: %v", err))
    }
    return id
}
func NewSpinLock() sync.Locker {
    var lock spinLock
    return &lock
}

自旋锁的其他变种

1. TicketLock

TicketLock主要解决的是公平性的问题。

思路:每当有线程获取锁的时候,就给该线程分配一个递增的id,我们称之为排队号,同时,锁对应一个服务号,每当有线程释放锁,服务号就会递增,此时如果服务号与某个线程排队号一致,那么该线程就获得锁,由于排队号是递增的,所以就保证了最先请求获取锁的线程可以最先获取到锁,就实现了公平性。

可以想象成银行办业务排队,排队的每一个顾客都代表一个需要请求锁的线程,而银行服务窗口表示锁,每当有窗口服务完成就把自己的服务号加一,此时在排队的所有顾客中,只有自己的排队号与服务号一致的才可以得到服务。

2. CLHLock

CLH锁是一种基于链表的可扩展、高性能、公平的自旋锁,申请线程只在本地变量上自旋,它不断轮询前驱的状态,如果发现前驱释放了锁就结束自旋,获得锁。

3. MCSLock

MCSLock则是对本地变量的节点进行循环。

4. CLHLock 和 MCSLock

都是基于链表,不同的是CLHLock是基于隐式链表,没有真正的后续节点属性,MCSLock是显示链表,有一个指向后续节点的属性。

将获取锁的线程状态借助节点(node)保存,每个线程都有一份独立的节点,这样就解决了TicketLock多处理器缓存同步的问题。

自旋锁与互斥锁

  • 自旋锁与互斥锁都是为了实现保护资源共享的机制。
  • 无论是自旋锁还是互斥锁,在任意时刻,都最多只能有一个保持者。
  • 获取互斥锁的线程,如果锁已经被占用,则该线程将进入睡眠状态;获取自旋锁的线程则不会睡眠,而是一直循环等待锁释放。

总结

  • 自旋锁:线程获取锁的时候,如果锁被其他线程持有,则当前线程将循环等待,直到获取到锁。
  • 自旋锁等待期间,线程的状态不会改变,线程一直是用户态并且是活动的(active)。
  • 自旋锁如果持有锁的时间太长,则会导致其它等待获取锁的线程耗尽CPU。
  • 自旋锁本身无法保证公平性,同时也无法保证可重入性。
  • 基于自旋锁,可以实现具备公平性和可重入性质的锁。
  • TicketLock:采用类似银行排号叫好的方式实现自旋锁的公平性,但是由于不停的读取serviceNum,每次读写操作都必须在多个处理器缓存之间进行缓存同步,这会导致繁重的系统总线和内存的流量,大大降低系统整体的性能。
  • CLHLock和MCSLock通过链表的方式避免了减少了处理器缓存同步,极大的提高了性能,区别在于CLHLock是通过轮询其前驱节点的状态,而MCS则是查看当前节点的锁状态。
  • CLHLock在NUMA架构下使用会存在问题。在没有cache的NUMA系统架构中,由于CLHLock是在当前节点的前一个节点上自旋,NUMA架构中处理器访问本地内存的速度高于通过网络访问其他节点的内存,所以CLHLock在NUMA架构上不是最优的自旋锁。

到此这篇关于Golang自旋锁的相关介绍的文章就介绍到这了,更多相关Golang自旋锁内容请搜索编程网以前的文章或继续浏览下面的相关文章希望大家以后多多支持编程网!

您可能感兴趣的文档:

--结束END--

本文标题: Golang自旋锁的相关介绍

本文链接: https://www.lsjlt.com/news/121209.html(转载时请注明来源链接)

有问题或投稿请发送至: 邮箱/279061341@qq.com    QQ/279061341

本篇文章演示代码以及资料文档资料下载

下载Word文档到电脑,方便收藏和打印~

下载Word文档
猜你喜欢
  • Golang自旋锁的相关介绍
    目录自旋锁golang实现自旋锁可重入的自旋锁和不可重入的自旋锁自旋锁的其他变种1. TicketLock2. CLHLock3. MCSLock4. CLHLock 和 MCSLo...
    99+
    2024-04-02
  • 介绍golang的%用法及相关知识
    在Go语言中,我们经常会用到%来进行格式化输出操作,%用法非常灵活,下面我们就来介绍一下golang的%用法及相关知识。基本用法:%用法最基本的形式就是用它将变量替换为指定的格式。例如下面代码将i替换为%d,%d表示输出变量i为十进制整数。...
    99+
    2023-05-14
  • MySQL数据库锁机制的相关原理介绍
    这篇文章主要讲解了“MySQL数据库锁机制的相关原理介绍”,文中的讲解内容简单清晰,易于学习与理解,下面请大家跟着小编的思路慢慢深入,一起来研究和学习“MySQL数据库锁机制的相关原理介绍”吧!  不同于行...
    99+
    2024-04-02
  • golang自旋锁怎么实现
    Golang中的自旋锁可以通过sync包中的Mutex类型来实现。Mutex类型提供了两个方法:Lock()用于获取锁,Unlock...
    99+
    2023-10-26
    golang
  • 关于Rocky Linux的相关介绍
    这篇文章主要介绍了关于Rocky Linux的相关介绍,具有一定借鉴价值,需要的朋友可以参考下。下面就和我一起来看看吧。Rocky Linux是一个社区企业操作系统,其下游合作伙伴已改变方向,旨在与美国顶级企业Linux发行版实现100%错...
    99+
    2023-06-08
  • MySQL中的相关工具介绍
    这篇文章主要介绍“MySQL中的相关工具介绍”,在日常操作中,相信很多人在MySQL中的相关工具介绍问题上存在疑惑,小编查阅了各式资料,整理出简单好用的操作方法,希望对大家解答”MySQL中的相关工具介绍”...
    99+
    2024-04-02
  • Golang分布式锁详细介绍
    目录进程内加锁trylock基于redis的setnx基于zk基于etcdredlock如何选择在单机程序并发或并行修改全局变量时,需要对修改行为加锁以创造临界区。为什么需要加锁呢?...
    99+
    2024-04-02
  • CentOS6.3启动的相关知识介绍
    这篇文章主要介绍“CentOS6.3启动的相关知识介绍”,在日常操作中,相信很多人在CentOS6.3启动的相关知识介绍问题上存在疑惑,小编查阅了各式资料,整理出简单好用的操作方法,希望对大家解答”CentOS6.3启动的相关知识介绍”的疑...
    99+
    2023-06-10
  • Amoeba相关产品及其介绍
    Amoeba for MySQL致力于MySQL的分布式数据库前端代理层,它主要在应用层访问MySQL的时候充当query 路由功能,专注 分布式数据库 proxy 开发。座落与Client、DB Serv...
    99+
    2024-04-02
  • PHP中的日期相关函数介绍
    这篇文章主要介绍“PHP中的日期相关函数介绍”,在日常操作中,相信很多人在PHP中的日期相关函数介绍问题上存在疑惑,小编查阅了各式资料,整理出简单好用的操作方法,希望对大家解答”PHP中的日期相关函数介绍”的疑惑有所帮助!接下来,请跟着小编...
    99+
    2023-06-20
  • Shell时间date相关的命令介绍
    这篇文章主要讲解了“Shell时间date相关的命令介绍”,文中的讲解内容简单清晰,易于学习与理解,下面请大家跟着小编的思路慢慢深入,一起来研究和学习“Shell时间date相关的命令介绍”吧!date +%Fdate ...
    99+
    2023-06-09
  • linux shell数组的相关知识介绍
    本篇内容主要讲解“linux shell数组的相关知识介绍”,感兴趣的朋友不妨来看看。本文介绍的方法操作简单快捷,实用性强。下面就让小编来带大家学习“linux shell数组的相关知识介绍”吧!数组的声明:1)array[key]=val...
    99+
    2023-06-09
  • Python中字典的相关操作介绍
    字典的添加与修改 # coding:utf-8 if __name__ == '__main__': example = {'name': 'xie', 'age': 27...
    99+
    2024-04-02
  • php时间戳的转换的相关介绍
    时间戳是指Unix操作系统的时间格式,它基于1970年01月01日00时00分00秒(UTC/GMT)的秒数。由于这种格式易于计算和比较,因此时间戳被广泛用于网络编程和数据库应用中。在PHP中,时间戳可以通过简单的函数调用而轻松地转换为可读...
    99+
    2023-05-14
    php
  • 【MongoDB】3.0 配置文件相关介绍
    概述:在启动mongod和mongos时可以通过配置文件来启动控制实例。该配置文件包含的设置同等于mongod和mongos命令选项。使用配置文件管理mongod和mongos更容易,特别是对于大规模部署。...
    99+
    2024-04-02
  • ASP.NET Core扩展库的相关功能介绍
    目录简介日志扩展轻量级实体映射AspNetCore Http服务端的扩展HttpClient扩展令牌提供器并行队列处理亲爱的.Neter们,在我们日复一日的编码过程中是不是会遇到一些...
    99+
    2024-04-02
  • golang的map介绍
    Go语言中map是一种无序的键值对集合,也被称为哈希表或字典,map使用哈希算法实现,可以高效地进行插入、查找和删除操作,需要注意的是,map是一个引用类型,当将map传递给函数或赋值给其他变量时,实际上是传递了map的引用,多个变量共享同...
    99+
    2023-12-18
    go语言 Golang golang的map
  • win10如何彻底关掉自动锁屏win10如何彻底关掉自动锁屏方式详细介绍
    win10如何彻底关掉自动锁屏是一些不希望win10自动锁屏危害应用的用户想解决的问题,用户们使用win10的情况下假如一段时间并没有实际操作得话显示屏可能进到自动锁屏的情况,有点儿相近锁屏,那样怎样关掉这一自动锁屏呢,用户们只必须根据下列...
    99+
    2023-07-10
  • Golang函数的锁类型介绍和应用方法
    Golang 函数的锁类型介绍和应用方法Go 编程语言是一种高效、可扩展、并发安全的语言,而并发安全正是 Golang 的一大亮点。我们通常会在开发过程中使用锁来确保线程安全,Golang 的标准库提供了多种类型的锁,用于不同的场景。在本文...
    99+
    2023-05-18
    Golang 应用方法 函数锁
  • PHP日期相关函数的介绍及用法
    这篇文章主要介绍“PHP日期相关函数的介绍及用法”,在日常操作中,相信很多人在PHP日期相关函数的介绍及用法问题上存在疑惑,小编查阅了各式资料,整理出简单好用的操作方法,希望对大家解答”PHP日期相关函数的介绍及用法”的疑惑有所帮助!接下来...
    99+
    2023-06-20
软考高级职称资格查询
编程网,编程工程师的家园,是目前国内优秀的开源技术社区之一,形成了由开源软件库、代码分享、资讯、协作翻译、讨论区和博客等几大频道内容,为IT开发者提供了一个发现、使用、并交流开源技术的平台。
  • 官方手机版

  • 微信公众号

  • 商务合作