Mutex:互斥锁源码解读

Mutex

count++操作问题

count++是非原子操作,所以有并发问题

什么是原子操作

所谓原子操作是指不会被线程调度机制打断的操作;这种操作一旦开始,就一直运行到结束,中间不会有任何 context switch(操作系统保证)。所以原子操作在单处理器中是没有并发问题的。

但是光靠系统,无法保证多处理器下原子操作的并发安全
例子:
以decl (递减指令)为例,这是一个典型的"读-改-写"过程,涉及两次内存访问。设想在不同CPU运行的两个进程都在递减某个计数值,可能发生的情况是:
⒈ CPU A(CPU A上所运行的进程,以下同)从内存单元把当前计数值⑵装载进它的寄存器中;
⒉ CPU B从内存单元把当前计数值⑵装载进它的寄存器中。
⒊ CPU A在它的寄存器中将计数值递减为1;
⒋ CPU B在它的寄存器中将计数值递减为1;
⒌ CPU A把修改后的计数值⑴写回内存单元。
⒍ CPU B把修改后的计数值⑴写回内存单元。

所以,多处理器下原子操作的并发安全需要硬件的支持,和CPU的架构有关:
在x86 平台上,CPU提供了在指令执行期间对总线加锁的手段。如果汇编语言的程序中在一条指令前面加上前缀"LOCK",经过汇编以后的机器代码就使CPU在执行这条指令的时候把总线锁住,这样同一总线上别的CPU就暂时不能通过总线访问内存了,保证了这条指令在多处理器环境中的并发安全。

可以加LOCK前缀的指令:
只有ADD, ADC, AND, BTC, BTR, BTS, CMPXCHG(CAS操作),DEC, INC, NEG, NOT, OR, SBB, SUB, XOR, XADD 和 XCHG指令前面可以加"LOCK"指令,实现原子操作

atomic解决count++问题

atomic是GO提供的原子操作包,这里的count++就可以使用atomic.Add(),这样就可以保证count值增加1的并发安全

CAS的ABA问题

假设有两个线程T1和T2,这两个线程对同一个栈进行出栈和入栈的操作
在这里插入图片描述
出栈操作:CAS(SP, newSP)
入栈操作:CAS(SP, newEle)
SP代表栈顶,newSP代表栈顶下一个元素
T1、T2操作前,栈为A->B->C
T1先准备出栈,拿到SP是A,newSP是B,执行CAS(A, B),执行CAS前B先执行了出栈、出栈、再把A入栈,栈变为A->C
这时T1执行CAS(A, B),因为当前的SP还是A,所以栈顶就变为了B,但是和预期不符,现在链表上只有A、C,T1出栈后栈顶应该是C

解决ABA问题的手段

加一个版本号,每次修改值的时候先使用CAS操作修改版本号,只有版本号修改成功才可以使用CAS操作修改值

假设初始版本号是1
这样之前的出栈、入栈问题,T1的操作就是CAS(expected oldValue A, newValue B, expected oldVersion 1, newVersion 2),T2三次栈操作后version变为4,T1的CAS操作就会失败

References

https://blog.csdn.net/qq_35492857/article/details/78471032
https://blog.csdn.net/weixin_42914675/article/details/103983870

Mutex演进

初版Mutex

使用一个flag变量表示申请锁的goroutine数量
加锁时使用CAS操作设置flag变量的值为当前值+1,如果+1后的值是1那么证明拿到锁,否则阻塞等待
解锁时使用CAS操作设置flag变量的值为当前值-1, 如果-1后的值是0那么证明没有等待者,否则说明有等待者那么唤醒等待者

由于每次加锁是将锁变量的值+1,所以如果有等待者那么新来的goroutine就拿不到锁

type Mutex struct {
	key int32
	sema int32  //信号量,用来阻塞、唤醒goroutine
}

func (m *Mutex)Lock() {
	for {
		if xadd(&m.key, 1) == 1 {
			return
		}
		runtime_semacquire(&m.sema)
	}
}

fun xadd(value *int, delta int) int {
	for {
		if cas(value, *value, *value+delta) {
			return *value+delta
		}
	}
}

func (m *Mutex)UnLock() {
	if xadd(&m.key, -
  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 1
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值