0

0

Golang中的指针与并发编程_Golang指针与并发安全操作分析

P粉602998670

P粉602998670

发布时间:2026-02-06 10:59:02

|

382人浏览过

|

来源于php中文网

原创

直接传指针进goroutine易出错,因循环变量复用导致所有goroutine共享同一地址;sync.Mutex不保护指针本身而只保护临界区内的解引用操作;unsafe.Pointer绕过GC跟踪易致悬垂指针;channel传指针需明确所有权与生命周期。

golang中的指针与并发编程_golang指针与并发安全操作分析

为什么直接传指针进 goroutine 容易出错

因为 goroutine 启动是异步的,如果循环中用 &v 取地址并启动 goroutine,所有 goroutine 最终可能都指向同一个内存地址(即循环变量 v 的最后一轮值)。

  • 典型现象:for _, v := range items { go func() { fmt.Println(v) }() } 输出全是最后一个 v
  • 根本原因:Go 中 range 复用循环变量,&v 总是取同一块地址
  • 修复方式:在循环体内显式拷贝变量,比如 go func(val int) { fmt.Println(val) }(v),或用局部变量 val := v; go func() { ... }(val)
  • 注意:即使传的是结构体指针,只要它指向的是循环内反复赋值的变量,问题依旧存在

sync.Mutex 保护指针所指向的数据,不是保护指针本身

指针变量本身是可复制的,sync.Mutex 不能靠“锁住指针”来保证并发安全;必须确保所有对指针所指向内存的读写,都在临界区内完成。

  • 错误写法:var p *int; mu.Lock(); p = &x; mu.Unlock() —— 这只锁了赋值动作,后续通过 p 读写仍不安全
  • 正确做法:把所有解引用操作(*p)包进 mu.Lock()/Unlock() 区间
  • 常见陷阱:把 mutex 放在结构体里但没导出,外部无法调用 Lock();或误以为 “指针+mutex 字段” 就自动线程安全
  • 性能提示:避免在 hot path 中频繁加锁解引用;考虑用 sync/atomic 操作简单类型(如 *int32),但仅限原子读写,不支持复合操作

unsafe.Pointer 转换指针类型时丢失类型安全与 GC 可见性

在并发场景下混用 unsafe.Pointer 和普通指针,容易导致 GC 误判对象存活状态,引发悬垂指针或提前回收。

  • 典型错误:p := &x; up := unsafe.Pointer(p); ... go func() { *(*int)(up) = 42 }() —— 若 x 是局部变量且函数已返回,up 指向的内存可能被回收
  • GC 不跟踪 unsafe.Pointer,也不会将其视为根对象;一旦没有其他 Go 指针指向该内存,就可能被清理
  • 并发下更危险:一个 goroutine 正在用 unsafe 访存,另一个触发 GC,且无强引用维持对象生命周期
  • 替代方案:优先用 sync.Pool 管理临时对象;必须用 unsafe 时,确保原始 Go 指针在整个使用周期内持续存活(例如全局变量、堆分配对象)

channel 传递指针需明确所有权和生命周期边界

通过 channel 发送指针,本质是传递内存地址,接收方获得的是同一份数据的访问权。谁负责释放?是否允许并发读写?必须由设计者约定清楚。

稿定AI
稿定AI

拥有线稿上色优化、图片重绘、人物姿势检测、涂鸦完善等功能

下载

立即学习go语言免费学习笔记(深入)”;

  • 常见误用:发送指向栈变量的指针(如 func() { x := 42; ch ),接收方收到后 x 已失效
  • 安全前提:指针必须指向堆分配对象(如 new(T)&struct{}),且生命周期长于 channel 传输和消费过程
  • 并发风险:多个 goroutine 从 channel 收到同一指针后同时修改,等价于裸指针共享,仍需额外同步机制
  • 建议:除非有明确性能收益(如大结构体),否则优先传值;若必须传指针,配合 sync.Once 或文档注明“该指针仅由接收方独占使用”

指针本身不并发安全,安全与否取决于你怎么用它——尤其是它指向哪儿、谁在什么时候访问、有没有其他 goroutine 在同一时间做别的事。最容易被忽略的,是那些看起来“只是读一下”的解引用操作,在并发路径里也可能成为竞态源头。

热门AI工具

更多
DeepSeek
DeepSeek

幻方量化公司旗下的开源大模型平台

豆包大模型
豆包大模型

字节跳动自主研发的一系列大型语言模型

通义千问
通义千问

阿里巴巴推出的全能AI助手

腾讯元宝
腾讯元宝

腾讯混元平台推出的AI助手

文心一言
文心一言

文心一言是百度开发的AI聊天机器人,通过对话可以生成各种形式的内容。

讯飞写作
讯飞写作

基于讯飞星火大模型的AI写作工具,可以快速生成新闻稿件、品宣文案、工作总结、心得体会等各种文文稿

即梦AI
即梦AI

一站式AI创作平台,免费AI图片和视频生成。

ChatGPT
ChatGPT

最最强大的AI聊天机器人程序,ChatGPT不单是聊天机器人,还能进行撰写邮件、视频脚本、文案、翻译、代码等任务。

相关专题

更多
golang如何定义变量
golang如何定义变量

golang定义变量的方法:1、声明变量并赋予初始值“var age int =值”;2、声明变量但不赋初始值“var age int”;3、使用短变量声明“age :=值”等等。本专题为大家提供相关的文章、下载、课程内容,供大家免费下载体验。

184

2024.02.23

golang有哪些数据转换方法
golang有哪些数据转换方法

golang数据转换方法:1、类型转换操作符;2、类型断言;3、字符串和数字之间的转换;4、JSON序列化和反序列化;5、使用标准库进行数据转换;6、使用第三方库进行数据转换;7、自定义数据转换函数。本专题为大家提供相关的文章、下载、课程内容,供大家免费下载体验。

231

2024.02.23

golang常用库有哪些
golang常用库有哪些

golang常用库有:1、标准库;2、字符串处理库;3、网络库;4、加密库;5、压缩库;6、xml和json解析库;7、日期和时间库;8、数据库操作库;9、文件操作库;10、图像处理库。本专题为大家提供相关的文章、下载、课程内容,供大家免费下载体验。

344

2024.02.23

golang和python的区别是什么
golang和python的区别是什么

golang和python的区别是:1、golang是一种编译型语言,而python是一种解释型语言;2、golang天生支持并发编程,而python对并发与并行的支持相对较弱等等。本专题为大家提供相关的文章、下载、课程内容,供大家免费下载体验。

210

2024.03.05

golang是免费的吗
golang是免费的吗

golang是免费的。golang是google开发的一种静态强类型、编译型、并发型,并具有垃圾回收功能的开源编程语言,采用bsd开源协议。本专题为大家提供相关的文章、下载、课程内容,供大家免费下载体验。

398

2024.05.21

golang结构体相关大全
golang结构体相关大全

本专题整合了golang结构体相关大全,想了解更多内容,请阅读专题下面的文章。

282

2025.06.09

golang相关判断方法
golang相关判断方法

本专题整合了golang相关判断方法,想了解更详细的相关内容,请阅读下面的文章。

196

2025.06.10

golang数组使用方法
golang数组使用方法

本专题整合了golang数组用法,想了解更多的相关内容,请阅读专题下面的文章。

621

2025.06.17

Golang处理数据库错误教程合集
Golang处理数据库错误教程合集

本专题整合了Golang数据库错误处理方法、技巧、管理策略相关内容,阅读专题下面的文章了解更多详细内容。

0

2026.02.06

热门下载

更多
网站特效
/
网站源码
/
网站素材
/
前端模板

精品课程

更多
相关推荐
/
热门推荐
/
最新课程
Go 教程
Go 教程

共32课时 | 4.7万人学习

Go语言实战之 GraphQL
Go语言实战之 GraphQL

共10课时 | 0.8万人学习

关于我们 免责申明 举报中心 意见反馈 讲师合作 广告合作 最新更新
php中文网:公益在线php培训,帮助PHP学习者快速成长!
关注服务号 技术交流群
PHP中文网订阅号
每天精选资源文章推送

Copyright 2014-2026 https://www.php.cn/ All Rights Reserved | php.cn | 湘ICP备2023035733号