Go错误集锦 | 字符串格式化竟然能引起死锁
2023-02-26 09:48:39 时间
今天跟大家分享一个关于格式化字符串时造成的死锁现象及对应的解决方案。以便大家在今后的研发中可以避免类似情况的出现。
假设我们有以下Customer结构体,该结构体的方法可以被并发访问。我们使用sync.RWMutex来保护并发读写。然后我们实现一个UpdateAge方法来更新Customer的age值,同时检查该age如果是负数,则使用fmt.Errorf返回一个格式化的字符串错误。同时,Customer还实现了Stringer接口的String方法。代码如下:
type Customer struct {
mutex sync.RWMutex
id string
age int
}
func (c *Customer) UpdateAge(age int) error {
c.mutex.Lock()
defer c.mutex.Unlock()
if age < 0 {
return fmt.Errorf("age should be positive for customer %s", c)
}
c.age = age
return nil
}
func (c *Customer) String() string {
c.mutex.RLock()
defer c.mutex.RUnlock()
return fmt.Sprintf("id %s, age %d", c.id, c.age)
}
上述代码有什么问题吗?
问题在于当我们调用UpdateAge方法时,有可能会产生死锁。因为若age是负数,那么会返回一个错误,又因为在错误中使用了%s对结构体实例进行字符串输出,所以会调用Customer的String方法。但是在UpdateAge中已经获取了互斥锁,还没来得及释放,在String中的c.mutex.RLock()就获取不到锁,并阻塞在这里,这样就造成了死锁。
这种问题应该怎么解决?
一种方法就是改进互斥锁的限制区域。实际上,在UpdateAge中,我们是先加锁,然后再判断age是否是负数。我们可以将二者交换,先判断age是否为负数,然后再进行加锁。如下:
func (c *Customer) UpdateAge(age int) error {
if age < 0 {
return fmt.Errorf("age should be positive for customer %s", c)
}
c.mutex.Lock()
defer c.mutex.Unlock()
c.age = age
return nil
}
这样,当age是负数并返回格式化的字符串时,就不会产生锁竞争从而导致死锁的问题。以上案例,希望能够帮助大家在实际的研发过程中避免再踩相同的坑。
欢迎关注「Go学堂」,让知识活起来
相关文章
- Taro框架实现微信登录及获取手机号和用户信息
- [koreader]statistics插件之博客阅读统计模块
- 蓝桥杯寒假集训第五天(子串分值和)
- Webpack解析文件和资源
- Webpack中的文件监听与热更新
- 【愚公系列】2023年01月 Dapr分布式应用运行时-Dapr的安装
- 视频处理系列︱利用达摩院ModelScope进行视频人物分割+背景切换(一)
- SAP UI5 FlexBox Layout 布局的概念和具体使用案例介绍试读版
- 如何配置 jad,让 Eclipse 可以自动显示反编译之后的 .class 源代码
- 使用 SAP UI5 3D Viewer 控件显示 3D 模型效果试读版
- 【Django | 爬虫 】收集某吧评论集成舆情监控(附源码)
- 自建服务器远程游玩PS5不踩坑指南
- Redis发布订阅和事务实现原理
- 第十四届蓝桥杯集训——数组(一维)
- IP协议重点总结(附实例)
- 浅谈单元测试
- 假如面试官问你Babel的原理该怎么回答1
- vivo 服务端监控体系建设实践
- 挖掘研发项目协作痛点 UniPro“串联”人和事
- 振弦采集模块辅助功能寄存器