这篇文章给大家分享的是有关并去发编程之互斥是什么的内容。小编觉得挺实用的,因此分享给大家做个参考。一起跟随小编过来看看吧。
我们比较常见的大型项目的设计中都会出现并发访问问题,并发就是为了解决数据的准确性,保证同一个临界区的数据只能被一个线程进行操作,日常中使用到的并发场景也是很多的:
- <李> <强>计数器强>:计数器结果不准确,李> <李> <强>秒杀系统强>:由于同一时间访问量比较大,导致的超卖;李> <李> <强>用户账户异常强>:同一时间支付导致的账户透支;李> <李> <强>缓冲区数据异常强>:更新缓冲区导致的数据混乱。李>
上面都是并发带来的数据准确性的问题,决绝方案就是使用<>强互斥锁>强,也就是今天并发编程中的所要描述的互斥锁并发原语。
实现机制
互斥锁互斥就是为了避免并发竞争建立的并发控制机制,其中有个“临界区”的概念。
在并发编程过程中,如果程序中一部分资源或者变量会被并发访问或者修改,为了避免并发访问导致数据的不准确,这部分程序需要率先被保护起来,之后操作,操作结束后去除保护,这部分被保护的程序就叫做<强>临界区强>。
引用><强>使用互斥锁,限定临界区只能同时由一个线程持有>强,若是临界区此时被一个线程持有,那么其他线程想进入到这个临界区的时候,就会失败或者等待释放锁,持有此临界区的线程退出,其他线程才有机会获得这个临界区。
去互斥临界区示意图
互斥是去语言中使用最广泛的同步原语,也称为并发原语,<强>解决的是并发读写共享资源,避免出现数据竞争数据竞赛问题强>。
基本使用
<>强互斥锁互斥提供了两个方法和锁解锁:进入到临界区使用锁方法加锁,退出临界区使用解锁方法释放锁。强>
类型储物柜接口{ Lock () 解锁()}func (m *互斥)锁()函数(m *互斥)解锁()<强>当一个goroutine调用锁方法获取到锁后,其他goroutine会阻塞在锁的调用上,直到当前获取到锁的goroutine释放锁。强>
接下来是一个计数器的例子,是由100个goroutine对计数器进行累加操作,最后输出结果:
包mainimport ( “fmt" “sync")函数main () { varμsync.Mutex countNum:=0//确认辅助变量是否都执行完成 var wg同步。WaitGroup//wg添加数目要和创建的协程数量保持一致 wg.Add (100) 我:=0;我& lt;100;我+ + { 去func () { 推迟wg.Done () j:=0;j & lt;1000;j + + { mu.Lock () countNum + + mu.Unlock () } }() } wg.Wait () fmt.Printf (“countNum: % d" countNum)}实际使用
很多时候互斥锁并不是单独使用的,而是嵌套在结构体中使用,作为结构体的一部分,<强>如果嵌入的结构有多个字段,我们一般会把互斥放在要控制的字段上面,然后使用空格把字段分隔开来。强>
<强>甚至可以把获取锁,释放锁,计数加一的逻辑封装成一个方法。强>
包mainimport ( “fmt" “sync")//线程安全的计数器类型计数器结构{ 相等物int 名称字符串 μsync.Mutex 计数uint64}//加一方法func (c *柜台)增加(){ c.mu.Lock () 推迟c.mu.Unlock () c。数+ +}//取数值方法线程也需要受保护func (c *柜台)数()uint64 { c.mu.Lock () 推迟c.mu.Unlock () 返回c。数}函数main () {//定义一个计数器 var柜台柜台var wg sync.WaitGroup wg.Add (100) 我:=0;我& lt;100;我+ + { 去func () { 推迟wg.Done () j:=0;j & lt;1000;j + + { counter.Incr () } }() } wg.Wait () fmt.Printf (“% d \ n" counter.Count ())}感谢各位的阅读!关于去并发编程之互斥是什么就分享到这里了,希望以上内容可以对大家有一定的帮助,让大家可以学到更多知识。如果觉得文章不错,可以把它分享出去让更多的人看到吧!
并去发编程之互斥是什么