Golang 中 sync/atomic 包的原子操作

2023-11-03

背景

Go中多协程的情况下, 要保证操作的原子性,一般要使用RWMutex或者Mutex, 但是锁使用起来比较复杂,还要考虑lock 和unlock 顺序和成对出现,不注意就容易出错。
于是在sync/atomic包中,把我们常用的一些操作封装成原子操作,提供了更加轻量级的解决方案

Add 方法

简介

提供了将两个操作数相加的方法, 共有以下方法

func AddInt32(addr *int32, delta int32) (new int32)
func AddUint32(addr *uint32, delta uint32) (new uint32)
func AddInt64(addr *int64, delta int64) (new int64)
func AddUint64(addr *uint64, delta uint64) (new uint64)
func AddUintptr(addr *uintptr, delta uintptr) (new uintptr

这里的 AddUint32, AddUint64, AddUintptr 的参数是无符号类型, 标识可以使用 - 来进行减法操作

示例

package main

import (
	"fmt"
	"sync/atomic"
	"time"
)
func main() {
	// 加法案例
	var count int32
	for i:= 0;i < 100 ; i++{
		go func() { atomic.AddInt32(&count,1) }()
	}
	// 等待协程执行完
	time.Sleep(5*time.Second)
	fmt.Println("ADD count:", count)
	// 减法案例
	var sub_param1  uint32 = 100
	var sub_param2  uint32 = 1
	for i:= 0;i < 100 ; i++{
			// 添加了 - , 表示减法, 只能作用于无符号类型变量
		go func() { atomic.AddUint32(&sub_param1,-sub_param2)}()
	}
	// 等待协程执行完
	time.Sleep(5*time.Second)
	fmt.Println("SUB sub_param1:", sub_param1)
}

执行结果:
在这里插入图片描述
可以看到, 使用atomic操作更加简洁和方便.

其他方法

类似于Add, atomic 也提供了其他原子操作方法

Swap 方法,Swap 方法的功能是原值替换为新值,并返回原值。

func SwapInt32(addr *int32, new int32) (old int32)
func SwapInt64(addr *int64, new int64) (old int64)
func SwapUint32(addr *uint32, new uint32) (old uint32)
func SwapUint64(addr *uint64, new uint64) (old uint64)
func SwapUintptr(addr *uintptr, new uintptr) (old uintptr)
func SwapPointer(addr *unsafe.Pointer, new unsafe.Pointer) (old unsafe.Pointer)

CompareAndSwap 方法,功能是比较 addrold, 相等将addr的值替换为new, 返回值是是否进行了替换.

func CompareAndSwapInt32(addr *int32, old, new int32) (swapped bool)
func CompareAndSwapInt64(addr *int64, old, new int64) (swapped bool)
func CompareAndSwapUint32(addr *uint32, old, new uint32) (swapped bool)
func CompareAndSwapUint64(addr *uint64, old, new uint64) (swapped bool)
func CompareAndSwapUintptr(addr *uintptr, old, new uintptr) (swapped bool)
func CompareAndSwapPointer(addr *unsafe.Pointer, old, new unsafe.Pointer) (swapped bool)

Load 方法是简单的提取操作

func LoadInt32(addr *int32) (val int32)
func LoadInt64(addr *int64) (val int64)
func LoadUint32(addr *uint32) (val uint32)
func LoadUint64(addr *uint64) (val uint64)
func LoadUintptr(addr *uintptr) (val uintptr)
func LoadPointer(addr *unsafe.Pointer) (val unsafe.Pointer)

Store 方式是写入操作, 将val写入 addr

func StoreInt32(addr *int32, val int32)
func StoreInt64(addr *int64, val int64)
func StoreUint32(addr *uint32, val uint32)
func StoreUint64(addr *uint64, val uint64)
func StoreUintptr(addr *uintptr, val uintptr)
func StorePointer(addr *unsafe.Pointer, val unsafe.Pointer)

还有一个属于Value类型的方法, 可以存取任何类型的数据, 相当于一个数据存取空间, 但是同一个 Value 类型的实例,只能存取一种类型的数据, 只要调用过一次 Store 方法,那么传入此方法的后续参数类型必须和之前传入参数的类型一致,否则会导致 panic

func (v *Value) Load() (x interface{})
func (v *Value) Store(x interface{})
本文内容由网友自发贡献,版权归原作者所有,本站不承担相应法律责任。如您发现有涉嫌抄袭侵权的内容,请联系:hwhale#tublm.com(使用前将#替换为@)

Golang 中 sync/atomic 包的原子操作 的相关文章

  • 是否可以在 Golang 中 pickle 结构实例

    我正在 Golang 中做一些机器学习 我现在碰壁了 我训练有素的分类器需要将近半分钟的时间来训练 并且想要保存分类器的该实例 这样我就不必每次都从头开始训练 在 Golang 中应该如何去做呢 仅供参考 我的分类器是一个结构 当我用 py
  • 防止使用 golang 服务器访问文件夹中的文件

    我在 golang 中有一个服务器可以处理这样的文件夹路径 fs http FileServer http Dir assets http Handle Images fs http ListenAndServe 8000 nil 但在这个
  • 如何获取文件的 ctime、atime、mtime 并更改它们

    如何使用 Go 获取文件的 ctime mtime atime 并更改它们 在 Go 1 1 2 中 os Stat只能获取mtime os Chtimes 可以更改 mtime 和 atime 但不能更改 ctime Linux ctim
  • golang sql 驱动程序的准备语句

    关于golang的sql driver 下面两条语句有什么区别 store DB is sql DB type rows err store DB Query SQL args err nil defer rows Close and st
  • 从 Go Slice 中选择一个随机值

    情况 我有一些值 需要从中随机选择一个值 然后我想将它与固定字符串连接起来 到目前为止 这是我的代码 func main create the reasons slice and append reasons to it reasons m
  • Google App Engine Golang 没有这样的文件或目录

    我正在用 Go 开发一个 Google App Engine 项目 并陷入了读取文件的困境 事实上 应用程序在本地运行得很好 然而 部署时 它会恐慌告诉我没有这样的文件或目录 这是我的 fileValue 方法 func fileValue
  • 数据库连接最佳实践

    我有一个使用 net http 的应用程序 我使用 http 注册了一些处理程序 这些处理程序需要从数据库中获取一些内容 然后才能继续编写响应并完成请求 我的问题是连接到该数据库的最佳实践是什么 我希望它能够以每分钟 1 个请求或每秒 10
  • 如何自定义解析错误的 HTTP 400 响应?

    我编写了一个 REST API 服务 要求所有响应均为 JSON 但是 当 Go HTTP 请求解析器遇到错误时 它会返回 400 作为纯文本响应 而不会调用我的处理程序 例子 gt curl i H Authorization Basic
  • runtime.LockOSThread 是否允许子 goroutine 在同一个操作系统线程中运行?

    我明白在 Go 中 runtime LockOSThread https golang org pkg runtime LockOSThread将一个 goroutine 绑定到一个操作系统线程 并且不允许其他 goroutine 在该线程
  • GoLang - 坚持使用 ISO-8859-1 字符集

    我正在开发一个项目 我们需要将信息保存在具有 ISO 8859 1 表的旧数据库中 因此 在向数据库写入内容之前 我需要将其从 UTF 8 转换为 ISO 8859 1 每次从数据库检索它时 我都需要将其转换回 UTF 8 我试图使用图书馆
  • 如何在 Visual Studio Code 中为 Golang 启用竞争检测器?

    我搜索了很多网页来找到我应该放入哪个短语settings json在 VS Code Golang 扩展 由 Microsoft 发布 中添加构建标志 在我的例子中是竞赛检测器 I added go buildFlags race 在扩展名
  • Go MSSQL 连接

    如何提供 MSSQL 连接 它说它始终与代码相关 即使信息不正确 也不会报错 package main import database sql fmt github com denisenkom go mssqldb log var ser
  • Go API 在 html 中显示 swagger api 规范 (json) (Swagger UI)

    我有一个服务于特定端口的应用程序 gorilla mux 我也有一个 json 文件形式的 swagger API 规范 是否有任何 go API 可以像 spring boot 一样从 JSON 文件生成 swagger UI 定义 我正
  • OpenMP while 循环中的手动同步

    我最近开始使用 OpenMP 为大学的一个项目做一些 研究 我有一个矩形且均匀分布的网格 在该网格上我使用迭代方案求解偏微分方程 因此 我基本上有两个 for 循环 网格的 x 方向和 y 方向各一个 并由 while 循环包裹以进行迭代
  • 如何在 Goji (Golang) 中使用不同的中间件创建单独的路由组?

    我正在使用Goji https github com zenazn goji https github com zenazn goji 并希望定义具有自己的中间件的路由组 例如 下面的所有路径 company应使用 LDAP 身份验证并定义
  • 为什么我的 SQL 占位符没有被替换(使用 Go pq)?

    根据文档 我正在这样做 var thingname string asdf var id int err database QueryRow SELECT id from things where thing thingname Scan
  • 无法通过键获取 Gorilla 会话值

    我无法通过这种方式从会话中获取价值 它是nil session initSession r valWithOutType session Values key 完整代码 package main import fmt github com
  • 完全删除使用“go get”安装的软件包?

    我正在使用 Go 1 13 1 最新版本 我正在尝试完全删除我安装的软件包go get来自 GitHub 这go clean i
  • 使用 OpenTelemetry 统一不同服务的范围

    我刚刚开始使用 OpenTelemetry 并为此创建了两个 微 服务 Standard and GeoMap 最终用户将请求发送到Standard服务 该服务又将请求发送到GeoMap在将结果返回给最终用户之前获取信息 我使用 gRPC
  • 为什么 Go 中只有 int 而没有 float?

    在 Go 中 有这样的类型int这可能相当于int32 or int64取决于系统架构 我可以声明一个整数变量而不用担心它的大小 var x int 为什么没有这个类型float 这相当于float32 or float64取决于我的系统架

随机推荐

  • 什么是计算机网络中的127.0.0.1 IP地址或Localhost?

    IP addresses are used to specify the hosts in a numeric way There are different types of IP addresses in Computer networ
  • 听说渲影很便宜,是真的吗?

    这次我比较了3个平台 炫云 渲影和渲染100 首先说结论 渲影是很便宜 但也没便宜过渲染100 而且出图大小有猫腻 具体的往下看 首先我选取了一个219M的场景 不是很大 设置的分辨率是3200 4000 提交3个平台的时候选择的参数也一样
  • 《C++标准库》学习笔记 — STL — 并发 — 线程同步与并发 — mutex 与 lock

    C 标准库 学习笔记 STL 并发 线程同步与并发 mutex 与 lock 一 线程同步与并发并发问题 1 出错情况 1 未同步化的数据访问 2 写至半途的数据 3 重新安排的语句 2 解决问题需要的特性 3 C 并发的支持 二 Mute
  • C#中仿QQ截图

    欢迎大家提出意见 一起讨论 转载请标明是引用于 http blog csdn net chenyujing1234 代码 VS2008 http www rayfile com zh cn files bad4b357 978a 11e1
  • cmake使用教程(七)-流程和循环

    cmake系列使用教程 cmake使用教程 一 起步 cmake使用教程 二 添加库 cmake使用教程 三 安装 测试 系统自检 cmake使用教程 四 文件生成器 cmake使用教程 五 cpack生成安装包 cmake使用教程 六 蛋
  • TVS管原理和特性

    介绍TVS管的资料太多 中文的也有非常多 不过大多数的都是翻译的 在文章最后有所有文件的目录和下载 这里主要介绍原理特性和参数 然后画一些时间分析一下散热选取 最后把PCB总结一下 瞬态二极管 TVS Transient Voltage S
  • JavaWeb实现记住密码功能(使用Cookie)

    JavaWeb实现记住密码功能 使用Cookie 1 Cookie知识点 cookie介绍 背景 HTTP协议作是 状态协议 状态指每次request请求之前是相互独 的 当前请求 并不会记录它的上 次请求信息 存在这样的问题 既然 状态
  • 内联函数

    引入内联函数的目的是为了解决程序中函数调用的效率问题 函数是一种更高级的抽象 它的引入使得编程者只关心函数的功能和使用方法 而不必关心函数功能的具体实现 函数的引入可以减少程序的目标代码 实现程序代码和数据的共享 但是 函数调用也会带来降低
  • 【实践经验】cp 错误:cannot create regular file ‘../../src/ood1.jpg‘: No such file or directory

    今日在linux拷贝文件的时候 出现这个错误感觉很奇怪 命名目标目录是存在的 但是为什么会报错呢 其实出现这个问题的原因是 你所看到的目录结构可能不是真正的目录结构 比如我在拷贝的时候执行的命令是 cp 806252c538fffb0948
  • uniapp App调试及更新

    uniapp App专题 本章主要对App的调试方式 虚拟机 物理机 安装及更新方面进行总结 连接设备进行调试 准备工作 首先需要打开设备的开发者模式 设置中找到版本号 连续点击版本号直到出现提示 您现在已处于开发者模式 点击进入开发者选项
  • CocosCreator中的Prefab文件格式总结

    CocosCreator所有的Prefab都是以下类似的格式 我们学会用文本编辑器查看Prefab文件 可以帮助我们更轻松的查找节点 查看节点和组件信息 批量修改节点和组件信息等等 因为在文本编辑器中的Prefab文件才是原始的 而且Coc
  • 【clion】实现类似自定义代码自动补全的功能(懒人利器)

    比如我有句代码是经常要使用的 如下 freopen Users zhangkanqi Desktop 11 txt r stdin 但是自动补全里并没有这句话 网上也没有找到如何自定义自动补全的语句 学艺不精 可是我每次又懒得写这句话 因为
  • Java数据存储类型ArrayList、HashSet、HashMap、LinkedList使用不同遍历方法效率研究By Python

    Java不同数据存储类型使用不同遍历方法效率研究 GitHub代码仓库 数据存储类型 ArrayList HashSet HashMap LinkedList 遍历方法 传统遍历方法 for int i 0 i
  • 设计模式(三)工厂方法模式

    前一篇文章介绍了简单工厂模式 留下了一个疑问 如果需要扩展员工等级 有没有不修改既有接口的方式 答案就是工厂方法模式 既然员工的职级可以扩展 那创建对应职级员工的工厂是不是也可以扩展 工厂基类提供一个接口获取具体的产品 一旦有新的产品 就创
  • C++ day7

    简单vector include
  • CGAL 二维点集的凸包提取

    目录 一 凸包 二 代码实现 三 结果展示 一 凸包 用不严谨的话来讲 给定二维平面上的点集 凸包就是将最外层的点连接起来构成的凸多边形 它能包含点集中所有的点 百度百科 凸包 二 代码实现 include
  • 基于matlab和FFT算法实现信号频谱分析

    系列文章目录 数字信号处理 DSP Digital Signal Process 是电子通信领域非常重要的研究方向 博主汇总了数字信号处理 DSP 中常用的经典案例分析 主要基于算法分析 MATLAB程序实现 信号图像显示 对数字信号处理的
  • 算法竞赛入门经典(第二版)-刘汝佳-第十章 数学概念与方法 例题(16/29)

    文章目录 说明 例题 例10 1 例10 2 例10 3 例10 4 例10 5 未尝试 例10 6 例10 7 例10 8 例10 9 例10 10 例10 11 例10 12 例10 13 例10 14 例10 15 例10 16 未尝
  • platform设备驱动实验

    一 Linux 驱动的分离与分层 1 驱动的分隔与分离 传统驱动编写思路如下图 下图这个就是 Linux 中的总线 bus 驱动 driver 和设备 device 模型 也就是常说的驱动分离 2 驱动的分层 分层的目的也是为了在不同的层处
  • Golang 中 sync/atomic 包的原子操作

    背景 Go中多协程的情况下 要保证操作的原子性 一般要使用RWMutex或者Mutex 但是锁使用起来比较复杂 还要考虑lock 和unlock 顺序和成对出现 不注意就容易出错 于是在sync atomic包中 把我们常用的一些操作封装成