Go语言源码分析CAS的实现和Java如出一辙

看了Go的源码CAS这块实现和java还是类似的。 关于Java的分析参考: Java使用字节码和汇编语言同步分析volatile,synchronized的底层实现 都是使用汇编指令: LOCK+CMPXCHGL 原因很简单:单核肯定不能发挥Go的高并发性能,Go如果要支持多核,必然遇到并发编程数据可见性的问题,底层必然加锁。 无锁并不等于没有锁,只能说无重量级的锁而已。  

看了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 源代码解析(一) 锁机制的研究

知秋君
上一篇 2024-07-03 15:31
下一篇 2024-07-03 15:31

相关推荐