当前位置:首页 > 文章列表 > Golang > Go教程 > Go atomic.AndUint64 怎样原子清除状态位

Go atomic.AndUint64 怎样原子清除状态位

来源:17golang原创 2026-11-01 15:55:49 0浏览 收藏

要原子清除 uint64 状态字中的某几位,关键不是把待清除位直接传给 atomic.AndUint64,而是先取反得到保留掩码:keepMask := ^bitsToClear。然后执行 oldState := atomic.AndUint64(&state, keepMask)。这样按位 AND 会把目标位变成 0,同时保留其他位;返回值 oldState 是更新前的状态快照。

官方文档:https://pkg.go.dev/sync/atomic#AndUint64

如果要清除的状态位是 bitsToClear,就传入 ^bitsToClear。不要直接传待清除位,否则保留下来的位会被一起清零。

先把状态位和反掩码分清

可以把一个 uint64 看成一组并发状态标志。例如最低位表示在线,第二位表示有错误:

package main

import "sync/atomic"

const (
	// 用独立的位表示不同状态,便于组合成一个状态字。
	stateOnline uint64 = 1 

这里的 stateError 是“要清除的位”,^stateError 才是“要保留的位”。因为 AND 0 的结果一定是 0,AND 1 才能保持原值。

Go uint64 状态字、待清除状态位、反掩码与 atomic.AndUint64 地址的静态关系
图1:状态字、待清除位和反掩码的静态关系图,不是运行截图或验证结果。

调用 AndUint64 并读取旧状态

AndUint64 的签名是 func AndUint64(addr *uint64, mask uint64) (old uint64)。它对 *addr 做原子按位 AND,并返回旧值。返回旧值很有用:它能让调用方在一次原子更新中判断“清除之前”某个标志是否存在。

func clearFlags(state *uint64, bitsToClear uint64) (oldState uint64, wasSet bool) {
	// 反掩码中的 1 表示保留,0 表示清除对应状态位。
	keepMask := ^bitsToClear
	// oldState 是更新前快照,不是清除后的新状态。
	oldState = atomic.AndUint64(state, keepMask)
	// 只从旧快照判断目标位,避免并发更新改变判断依据。
	wasSet = oldState&bitsToClear != 0
	return oldState, wasSet
}

例如 bitsToClear 同时包含在线位和错误位时,两个目标位都会被清零,其余 62 位保持原值。wasSet 只说明清除前至少有一个目标位为 1,不代表清除后状态字仍然包含它们。

Go atomic.AndUint64 的状态地址、保留掩码、旧状态和清除前标志判断关系
图2:AndUint64 的输入、旧状态和调用方判断关系图,展示接口职责,不是运行流程截图。

把位清除封装成稳定的状态接口

业务代码不要到处手写取反表达式,可以把位定义和清除动作放在同一个类型附近。这样调用方只传“想撤销的状态”,不容易误把保留掩码传错。

type StateWord uint64

func (s *StateWord) Clear(bits uint64) (old StateWord) {
	// bits 表示调用方希望清除的位,方法内部负责转换为保留掩码。
	old = StateWord(atomic.AndUint64((*uint64)(s), ^bits))
	return old
}

func (s StateWord) Has(bits uint64) bool {
	// 读取快照时使用值接收者;复合状态判断仍需由更高层设计同步边界。
	return uint64(s)&bits != 0
}

这个封装解决的是位掩码表达的一致性,不会自动把多个普通字段读写变成事务,也不会替代锁。若业务需要“检查多个条件后再决定是否更新”,应重新审视整个状态转换是否需要 CAS 或互斥保护。

64 位对齐和 atomic.Uint64 的选择

官方文档提醒,在 ARM、386 和 32 位 MIPS 等平台上,通过旧式原子函数访问 64 位字时,调用方需要负责安排 64 位对齐;把 uint64 放在结构体中时尤其要留意布局。使用类型封装通常更清楚:

type State struct {
	// atomic.Uint64 自带适合原子访问的类型语义,且不能在首次使用后复制。
	flags atomic.Uint64
}

func (s *State) Clear(bits uint64) (old uint64) {
	// Uint64.And 与 AndUint64 的掩码规则相同:传入要保留的位。
	return s.flags.And(^bits)
}

atomic.Uint64.And 适合新代码,因为状态字段本身表达了“这是原子 uint64”,也减少了手动取地址和布局误用的机会。若需要兼容既有的 *uint64 API,atomic.AndUint64 仍然可以使用,但应把对齐和复制规则写进类型约定。

常见误区和速查表

场景正确做法原因
清除某些位AndUint64(addr, ^bitsToClear)目标位与 0 做 AND,其他位与 1 做 AND
判断清除前是否开启检查返回的 oldState&bitsToClear返回值是原子更新前的快照
新增原子状态字段优先考虑 atomic.Uint64类型语义和对齐边界更明确
复合条件更新评估 CAS 或锁一次 AND 只保证这次位更新原子

相关问题

直接传 bitsToClear 会怎样?

会把待清除位之外的大多数位清零,因为按位 AND 的 0 会清除对应位置。清除状态位时必须传反掩码。

返回值是更新后的状态吗?

不是。AndUint64 返回的是更新前的旧值;如果需要新值,应根据已知掩码推导,或在明确的同步边界下再次原子读取。

AndUint64 能替代所有锁吗?

不能。它只适合单个 64 位状态字的原子按位更新;跨字段不变量、复合检查和多步状态迁移仍需要更完整的同步方案。

记住一句话:要清除哪些位,就把这些位取反后交给 AND;要判断清除前的状态,就读取函数返回的旧值。新代码可用 atomic.Uint64.And 表达同样语义,并把原子字段的类型边界写得更清楚。

版本声明
本文转载于:17golang原创 如有侵犯,请联系study_golang@163.com删除
Go path/filepath.WalkDir 怎样跳过指定目录Go path/filepath.WalkDir 怎样跳过指定目录
上一篇
Go path/filepath.WalkDir 怎样跳过指定目录
Go fs.ReadLink 怎样读取虚拟文件系统里的符号链接
下一篇
Go fs.ReadLink 怎样读取虚拟文件系统里的符号链接
查看更多
最新文章
查看更多
课程推荐
  • 前端进阶之JavaScript设计模式
    前端进阶之JavaScript设计模式
    设计模式是开发人员在软件开发过程中面临一般问题时的解决方案,代表了最佳的实践。本课程的主打内容包括JS常见设计模式以及具体应用场景,打造一站式知识长龙服务,适合有JS基础的同学学习。
    543次学习
  • GO语言核心编程课程
    GO语言核心编程课程
    本课程采用真实案例,全面具体可落地,从理论到实践,一步一步将GO核心编程技术、编程思想、底层实现融会贯通,使学习者贴近时代脉搏,做IT互联网时代的弄潮儿。
    516次学习
  • 简单聊聊mysql8与网络通信
    简单聊聊mysql8与网络通信
    如有问题加微信:Le-studyg;在课程中,我们将首先介绍MySQL8的新特性,包括性能优化、安全增强、新数据类型等,帮助学生快速熟悉MySQL8的最新功能。接着,我们将深入解析MySQL的网络通信机制,包括协议、连接管理、数据传输等,让
    500次学习
  • JavaScript正则表达式基础与实战
    JavaScript正则表达式基础与实战
    在任何一门编程语言中,正则表达式,都是一项重要的知识,它提供了高效的字符串匹配与捕获机制,可以极大的简化程序设计。
    487次学习
  • 从零制作响应式网站—Grid布局
    从零制作响应式网站—Grid布局
    本系列教程将展示从零制作一个假想的网络科技公司官网,分为导航,轮播,关于我们,成功案例,服务流程,团队介绍,数据部分,公司动态,底部信息等内容区块。网站整体采用CSSGrid布局,支持响应式,有流畅过渡和展现动画。
    485次学习
查看更多
AI推荐
  • PubMedQA数据集详解:生物医学问答基准、功能与应用指南
    PubMedQA
    深入了解PubMedQA生物医学问答数据集,涵盖其核心功能、使用方法及在临床决策、药物研发等场景的应用,助力提升NLP模型性能。
    824次使用
  • H2O EvalGPT:开源LLM大模型评估与排行榜工具
    H2O EvalGPT
    H2O EvalGPT是H2O.ai推出的开源LLM评估平台,提供详细的大模型性能排行榜、行业特定基准测试及A/B测试功能,助您快速选择最适合项目的高性能大语言模型。
    820次使用
  • LMArena是什么?伯克利AI模型评估平台使用指南与功能解析
    LMArena
    LMArena是加州大学伯克利分校推出的AI模型匿名评测平台。通过盲测投票机制,用户可对比不同大模型回答并生成实时排行榜,助力开发者优化模型及用户选择最佳AI工具。
    906次使用
  • 斯坦福HELM:大语言模型Holistic Evaluation整体评估框架详解
    HELM
    深入了解斯坦福推出的HELM(Holistic Evaluation of Language Models)大模型评测体系。本文解析其核心功能、安装配置步骤及应用场景,涵盖准确性、公平性、鲁棒性等多维度指标,助力开发者全面优化语言模型性能。
    879次使用
  • MMBench详解:多模态大模型基准测试、功能特点与使用指南
    MMBench
    MMBench是由上海人工智能实验室等机构联合推出的多模态基准测试平台,提供细粒度能力评估、大规模数据集及VLMEvalKit工具。本文详细介绍其核心功能、安装使用方法及应用场景,助力开发者全面评估多模态模型性能。
    702次使用
微信登录更方便
  • 密码登录
  • 注册账号
登录即同意 用户协议 和 隐私政策
返回登录
  • 重置密码