首页 > 其他分享 >如何实现一个sync.Once

如何实现一个sync.Once

时间:2023-05-05 18:11:06浏览次数:30  
标签:初始化 Do sync 如何 done func Once

sync.Once 是 golang里用来实现单例的同步原语。Once 常常用来初始化单例资源,
或者并发访问只需初始化一次的共享资源,或者在测试的时候初始化一次测试资源。
单例,就是某个资源或者对象,只能初始化一次,类似全局唯一的变量。
一般都认为只要使用一个flag标记即可,然后使用原子操作这个flag,代码如下:

type XOnce struct {
	done uint32
}

func (x *XOnce) Do(f func()) {
	if atomic.CompareAndSwapUint32(&x.done, 0, 1)  {
		f()
	}
}

这种方式有很大的问题,就是如果参数f执行很慢,其他调用Do方法的goroutine,
虽然看到done已经设置过值,标记为已执行过,但是初始化资源的函数并未执行完,
在获取初始化资源的时候,可能会得到空的资源或者发生空指针的panic。

来看下go源码中是如何解决这个问题的。

type Once struct {
	m    sync.Mutex
	done uint32
}

func (x *Once) Do(f func()) {
	if atomic.LoadUint32(&x.done) == 0 {
		x.doSlow(f)
	}
}

func (x *Once) doSlow(f func()) {
	x.m.Lock()
	defer x.m.Unlock()

	if x.done == 0 {
		defer atomic.StoreUint32(&x.done, 1)
		f()
	}
}

Once类中有一个互斥锁和一个done标记。
用并发场景来校验一下,假设有两个goroutine同时调用Do方法,并进入doSlow,此时互斥锁的机制保证只有一个g能执行f。
同时利用双检查机制,再次判断x.done是否为,如果是0,则是第一次执行,执行完毕后,将x.done置为1,最后释放锁。
即时第二个g被唤醒了,但是由于此时的x.done==1,也就不会在执行f了。

双检查机制:既保证了并发的goroutine会等待f完成,而且还不会多次执行f

标签:初始化,Do,sync,如何,done,func,Once
From: https://www.cnblogs.com/panlq/p/17375021.html

相关文章

  • MySQL:如何实现主从复制?
    简介MySQL主从复制是一个异步的复制过程,底层是基于MySQL数据库自带的二进制日志功能。指一台或多台MySQL数据库(从库,slave)从另一台数据库(主库,master)进行日志的复制、日志解析,最终实现从库数据与主库数据保持一致。 原理1、master将改变记录到二进制日志中。2、slave将mast......
  • 如何配置Apple推送证书 push证书
     很多开发者使用hbuilder打包应该都有遇到这个问题,“profile文件不支持推通知功能,但manifest.json中选择了Push(消息推送)模块,请重新生成profile文件”。想要使用Apple的推送功能就需要配置push证书,然后使用快捷工具appuploader工具制作证书,最后使用hbuilder打包就可以了。......
  • 如何使用brew(Homebrew)
    #brew安装,如果安装速度慢或者被墙,可自行网上找镜像链接安装/bin/bash-c"$(curl-fsSLhttps://raw.githubusercontent.com/Homebrew/install/master/install.sh)"#常用命令brew-v#查看brew版本号brewinstallxxx#安装包brewsearchxxx#搜索包brewinfoxxx#......
  • keepalived如何手动切换主备
     概述主备部署中使用keepalived可以很方便的实现,安装维护简单,功能稳定。最近在使用过程中有小的发现,记录一下。环境CentOSLinuxrelease7.9.2009(Core)keepalived.x86_641.3.5-19.el7安装配置centos7自带的keepalived版本为1.3.5,直接使用yum安装sudoyuminstallk......
  • 代码大全-如何建立一个高质量的子程序
    不积硅步,无以至千里;不积小流,无以成江海。大型的项目是由一个个小模块构建而成。每一个小模块里面又包含着许多子程序。如果每一个子程序都能做到高质量,那么整个项目代码的质量必然很高。......
  • 如何在 AlmaLinux 8 上安装和使用 Docker
    Docker是面向开发人员和系统管理员的强大平台,可简化在软件容器内部署应用程序的过程。容器允许您将应用程序及其所有部分(代码、运行时、系统工具、系统库——通常位于/usr/bin或/usr/lib中的任何内容)打包,以便它可以在任何Linux机器上一致地运行。这包括操作系统内核和其......
  • 如何不显示我的电脑、回收站等图标?
      本文介绍将Windows电脑中的Administrator、网络、回收站等系统自带桌面图标取消显示或恢复显示的方法。  在Windows10电脑中,一般在桌面上默认会显示如下所示的一些系统自带图标。  然而,在上述这些图标中,有一些我们可能相对而言使用的频率比较低,比如网络图标,以及上图中......
  • 如何将应用图标固定在Ubuntu的快捷启动栏上
    一、将已有应用的图标固定在快捷启动栏上,步骤如下:1.在/usr/share/applications文件夹中找到相应的应用图标。2.单击应用程序图标并将其拖动到快捷启动栏上。3.释放鼠标按钮,应用程序图标将固定在快捷启动栏上。二、自定义快捷方式固定在快捷启动栏上,步骤如下:......
  • STM32单片机引脚要职能配置为输入或者输出模式,并不能像51一样准双向,那么如何进行但总
    如题随便找个端口举例对应的程序为 难道需要写之后立即初始化为输入?然后赶紧读?然后再赶紧初始化为输出?再往外写?是的,还真他妈就是这么傻逼的操作 ......
  • 23、MySQL压力测试及mysql如何在生产中配置主配置文件
    MySQL压力测试及mysql如何在生产中配置主配置文件测试工具mysqlslap跟上选项#mysql自带mysqlslap-a-uroot-p123456#单线程测试mysqlslap-a-c100-uroot-p123456#多线程并发测试(模拟100个客户端并发连接)mysqlslap-a--concurrency=50,100--number-o......