关于 Go 并发编程之 Mutex

发布时间:2024-01-20
下面由golang教程栏目给大家介绍 go 并发编程之 mutex,希望对需要的朋友有所帮助!
友情提示:此篇文章大约需要阅读 5分钟45秒,不足之处请多指教,感谢你的阅读。
我们比较常见的大型项目的设计中都会出现并发访问问题,并发就是为了解决数据的准确性,保证同一个临界区的数据只能被一个线程进行操作,日常中使用到的并发场景也是很多的:
计数器:计数器结果不准确;秒杀系统:由于同一时间访问量比较大,导致的超卖;用户账户异常:同一时间支付导致的账户透支;buffer 数据异常:更新 buffer 导致的数据混乱。
上面都是并发带来的数据准确性的问题,决绝方案就是使用互斥锁,也就是今天并发编程中的所要描述的 mutex 并发原语。
实现机制
互斥锁 mutex 就是为了避免并发竞争建立的并发控制机制,其中有个“临界区”的概念。
在并发编程过程中,如果程序中一部分资源或者变量会被并发访问或者修改,为了避免并发访问导致数据的不准确,这部分程序需要率先被保护起来,之后操作,操作结束后去除保护,这部分被保护的程序就叫做临界区。
使用互斥锁,限定临界区只能同时由一个线程持有,若是临界区此时被一个线程持有,那么其他线程想进入到这个临界区的时候,就会失败或者等待释放锁,持有此临界区的线程退出,其他线程才有机会获得这个临界区。
go mutex 临界区示意图
mutex 是 go 语言中使用最广泛的同步原语,也称为并发原语,解决的是并发读写共享资源,避免出现数据竞争 data race 问题。
基本使用
互斥锁 mutex 提供了两个方法 lock 和 unlock:进入到临界区使用 lock 方法加锁,退出临界区使用 unlock 方法释放锁。
type locker interface { lock() unlock()}func(m *mutex)lock()func(m *mutex)unlock()当一个 goroutine 调用 lock 方法获取到锁后,其他 goroutine 会阻塞在 lock 的调用上,直到当前获取到锁的 goroutine 释放锁。
接下来是一个计数器的例子,是由 100 个 goroutine 对计数器进行累加操作,最后输出结果:
package mainimport ( "fmt" "sync")func main() { var mu sync.mutex countnum := 0 // 确认辅助变量是否都执行完成 var wg sync.waitgroup // wg 添加数目要和 创建的协程数量保持一致 wg.add(100) for i := 0; i < 100; i { go func() { defer wg.done() for j := 0; j < 1000; j { mu.lock() countnum mu.unlock() } }() } wg.wait() fmt.printf("countnum: %d", countnum)}实际使用
很多时候 mutex 并不是单独使用的,而是嵌套在 struct 中使用,作为结构体的一部分,如果嵌入的 struct 有多个字段,我们一般会把 mutex 放在要控制的字段上面,然后使用空格把字段分隔开来。
甚至可以把获取锁、释放锁、计数加一的逻辑封装成一个方法。
package mainimport ( "fmt" "sync")// 线程安全的计数器type counter struct { countertype int name string mu sync.mutex count uint64}// 加一方法func (c *counter) incr() { c.mu.lock() defer c.mu.unlock() c.count }// 取数值方法 线程也需要受保护func (c *counter) count() uint64 { c.mu.lock() defer c.mu.unlock() return c.count}func main() { // 定义一个计数器 var counter counter var wg sync.waitgroup wg.add(100) for i := 0; i < 100; i { go func() { defer wg.done() for j := 0; j < 1000; j { counter.incr() } }() } wg.wait() fmt.printf("%d\\\\n", counter.count())}思考问题
q:你已经知道,如果 mutex 已经被一个 goroutine 获取了锁,其它等待中的 goroutine 们只能一直等待。那么,等这个锁释放后,等待中的 goroutine 中哪一个会优先获取 mutex 呢?
a:fifo,先来先服务的策略,go 的 goroutine 调度中,会维护一个保障 goroutine 运行的队列,当获取到锁的 goroutine 执行完临界区的操作的时候,就会释放锁,在队列中排在第一位置的 goroutine 会拿到锁进行临界区的操作。
上一个:苹果手机屏幕划不动的解决方法(苹果手机屏幕划动不了)
下一个:我经常被家暴怎么办

bohmer球阀fsk
Q611F三片式气动球阀
PERMA PURE干燥管
RTT12R27JTP现货库存,最新价格
劳动合同一定要法人签字吗
父母双方离婚之后抚养费如何计算
美国cr magnetics传感器
单通道数显仪表,数显仪表,迅鹏WPK6-B
合同纠纷被告不执行怎么办
Q41F-6S增强聚丙烯球阀产品介绍及尺寸规格