看了Go的源码CAS这块实现和java还是类似的。
关于Java的分析参考:Java使用字节码和汇编语言同步分析volatile,synchronized的底层实现
都是使用汇编指令:LOCK+CMPXCHGL
原因很简单:单核肯定不能发挥Go的高并发性能,Go如果要支持多核,必然遇到并发编程数据可见性的问题,底层必然加锁。
无锁并不等于没有锁,只能说无重量级的锁而已。
Go语言源码:
Go的CAS是调用CompareAndSwapInt32,
golang中的互斥锁定义在src/sync/mutex.go
:
// Lock locks m.
// If the lock is already in use, the calling goroutine
// blocks until the mutex is available.
func (m *Mutex) Lock() {
// Fast path: grab unlocked mutex.
if atomic.CompareAndSwapInt32(&m.state, 0, mutexLocked) {
if race.Enabled {
race.Acquire(unsafe.Pointer(m))
}
return
}
无锁操作CAS: Compare And Swap 比较并交换。
源码在/src/runtime/internal/atomic/asm_amd64.s
可以看到实际上底层还是通过lock来实现,关于lock可以参考intel处理器指令。
// Copyright 2015 The Go Authors. All rights reserved.
// Use of this source code is governed by a BSD-style
// license that can be found in the LICENSE file.
// Note: some of these functions are semantically inlined
// by the compiler (in src/cmd/compile/internal/gc/ssa.go).
#include "textflag.h"
// bool Cas(int32 *val, int32 old, int32 new)
// Atomically:
//if(*val == old){
//*val = new;
//return 1;
//} else
//return 0;
TEXT runtime∕internal∕atomic·Cas(SB),NOSPLIT,$0-17
MOVQptr+0(FP), BX
MOVLold+8(FP), AX
MOVLnew+12(FP), CX
LOCK
CMPXCHGLCX, 0(BX)
SETEQret+16(FP)
RET
// boolruntime∕internal∕atomic·Cas64(uint64 *val, uint64 old, uint64 new)
// Atomically:
//if(*val == *old){
//*val = new;
//return 1;
//} else {
//return 0;
//}
TEXT runtime∕internal∕atomic·Cas64(SB), NOSPLIT, $0-25
MOVQptr+0(FP), BX
MOVQold+8(FP), AX
MOVQnew+16(FP), CX
LOCK
CMPXCHGQCX, 0(BX)
SETEQret+24(FP)
RET
TEXT runtime∕internal∕atomic·Casuintptr(SB), NOSPLIT, $0-25
JMPruntime∕internal∕atomic·Cas64(SB)
TEXT runtime∕internal∕atomic·CasRel(SB), NOSPLIT, $0-17
JMPruntime∕internal∕atomic·Cas(SB)
TEXT runtime∕internal∕atomic·Loaduintptr(SB), NOSPLIT, $0-16
JMPruntime∕internal∕atomic·Load64(SB)
TEXT runtime∕internal∕atomic·Loaduint(SB), NOSPLIT, $0-16
JMPruntime∕internal∕atomic·Load64(SB)
TEXT runtime∕internal∕atomic·Storeuintptr(SB), NOSPLIT, $0-16
JMPruntime∕internal∕atomic·Store64(SB)
TEXT runtime∕internal∕atomic·Loadint64(SB), NOSPLIT, $0-16
JMPruntime∕internal∕atomic·Load64(SB)
TEXT runtime∕internal∕atomic·Xaddint64(SB), NOSPLIT, $0-24
JMPruntime∕internal∕atomic·Xadd64(SB)
// bool Casp1(void **val, void *old, void *new)
// Atomically:
//if(*val == old){
//*val = new;
//return 1;
//} else
//return 0;
TEXT runtime∕internal∕atomic·Casp1(SB), NOSPLIT, $0-25
MOVQptr+0(FP), BX
MOVQold+8(FP), AX
MOVQnew+16(FP), CX
LOCK
CMPXCHGQCX, 0(BX)
SETEQret+24(FP)
RET
// uint32 Xadd(uint32 volatile *val, int32 delta)
// Atomically:
//*val += delta;
//return *val;
TEXT runtime∕internal∕atomic·Xadd(SB), NOSPLIT, $0-20
MOVQptr+0(FP), BX
MOVLdelta+8(FP), AX
MOVLAX, CX
LOCK
XADDLAX, 0(BX)
ADDLCX, AX
MOVLAX, ret+16(FP)
RET
TEXT runtime∕internal∕atomic·Xadd64(SB), NOSPLIT, $0-24
MOVQptr+0(FP), BX
MOVQdelta+8(FP), AX
MOVQAX, CX
LOCK
XADDQAX, 0(BX)
ADDQCX, AX
MOVQAX, ret+16(FP)
RET
TEXT runtime∕internal∕atomic·Xadduintptr(SB), NOSPLIT, $0-24
JMPruntime∕internal∕atomic·Xadd64(SB)
TEXT runtime∕internal∕atomic·Xchg(SB), NOSPLIT, $0-20
MOVQptr+0(FP), BX
MOVLnew+8(FP), AX
XCHGLAX, 0(BX)
MOVLAX, ret+16(FP)
RET
TEXT runtime∕internal∕atomic·Xchg64(SB), NOSPLIT, $0-24
MOVQptr+0(FP), BX
MOVQnew+8(FP), AX
XCHGQAX, 0(BX)
MOVQAX, ret+16(FP)
RET
TEXT runtime∕internal∕atomic·Xchguintptr(SB), NOSPLIT, $0-24
JMPruntime∕internal∕atomic·Xchg64(SB)
TEXT runtime∕internal∕atomic·StorepNoWB(SB), NOSPLIT, $0-16
MOVQptr+0(FP), BX
MOVQval+8(FP), AX
XCHGQAX, 0(BX)
RET
TEXT runtime∕internal∕atomic·Store(SB), NOSPLIT, $0-12
MOVQptr+0(FP), BX
MOVLval+8(FP), AX
XCHGLAX, 0(BX)
RET
TEXT runtime∕internal∕atomic·StoreRel(SB), NOSPLIT, $0-12
JMPruntime∕internal∕atomic·Store(SB)
TEXT runtime∕internal∕atomic·Store64(SB), NOSPLIT, $0-16
MOVQptr+0(FP), BX
MOVQval+8(FP), AX
XCHGQAX, 0(BX)
RET
// voidruntime∕internal∕atomic·Or8(byte volatile*, byte);
TEXT runtime∕internal∕atomic·Or8(SB), NOSPLIT, $0-9
MOVQptr+0(FP), AX
MOVBval+8(FP), BX
LOCK
ORBBX, (AX)
RET
// voidruntime∕internal∕atomic·And8(byte volatile*, byte);
TEXT runtime∕internal∕atomic·And8(SB), NOSPLIT, $0-9
MOVQptr+0(FP), AX
MOVBval+8(FP), BX
LOCK
ANDBBX, (AX)
RET
这里还有其他处理器的汇编代码:
其实这篇文章写得也还可以:Golang 源代码解析(一) 锁机制的研究