Golang的Mutex是值传递还是引用传递?

为什么会有这个问题?

突然看到函数传参的问题,就想知道直接传参,Mutex是传值还是传引用

结论

值传递

Mutex定义

type Mutex struct {
	state int32
	sema  uint32
}

看下定义就知道了,结构体,而且里面的字段类型都是普通值类型,那函数传参如果不特定使用指针,那就是值传递

抛出一个问题

下面代码会报panic

func TestMutex1(t *testing.T) {
	mux := sync.Mutex{}
	mux.Lock()
	mux.Unlock()
	mux.Unlock()    //fatal error: sync: unlock of unlocked mutex
}

而这段代码不会:

func selfUnlock(mux sync.Mutex) {
	fmt.Printf("before selfUnlock: %p, %v\n", &mux, mux)
	mux.Unlock()
	fmt.Printf("after selfUnlock: %p, %v\n\n", &mux, mux)
}

func TestMutex2(t *testing.T) {
	mux := sync.Mutex{}
	fmt.Printf("init mutex: %p, %v\n", &mux, mux)
	mux.Lock()
	fmt.Printf("after lock: %p, %v\n\n", &mux, mux)
	selfUnlock(mux)
	selfUnlock(mux)
}

表面上看都是对同一个互斥锁进行了两次的解锁操作,但是后者没有发生panic,为什么?

执行一下TestMutex2就能看出结果:

=== RUN   TestMutex2
init mutex: 0xc0000162a8, {0 0}
after lock: 0xc0000162a8, {1 0}

before selfUnlock: 0xc0000162c0, {1 0}
after selfUnlock: 0xc0000162c0, {0 0}

before selfUnlock: 0xc0000162d8, {1 0}
after selfUnlock: 0xc0000162d8, {0 0}

--- PASS: TestMutex2 (0.00s)

首先三处的地址不一样,这是自然的,毕竟函数传参了,然后就是具体的值,发现两次在调用 unlock() 函数的时候传入的值都是 Mutex{1, 0},也就是说传进函数 selfUnlock 的锁都是处于 lock 的状态,这也就是为啥一个锁可以 unlock 两次而没有panic,实际上是因为值传递,已经是两个锁了

结论

Mutex 的传递是值传递

函数传参会发生值拷贝(也就是复制了锁的状态),所以一定注意在不同函数内操作同一个锁时需要主动使用指针进行传递,如下:

func selfUnlock3(mux *sync.Mutex) {
	fmt.Printf("before selfUnlock: %p, %v\n", mux, *mux)
	mux.Unlock()
	fmt.Printf("after selfUnlock: %p, %v\n\n", mux, *mux)
}

func TestMutex3(t *testing.T) {
	mux := sync.Mutex{}
	fmt.Printf("init mutex: %p, %v\n", &mux, mux)
	mux.Lock()
	fmt.Printf("after lock: %p, %v\n\n", &mux, mux)
	selfUnlock3(&mux)
	fmt.Printf("main after selfUnlock: %p, %v\n", &mux, mux)
}

指针传递,达到了在func内对Mutex解锁的目的!
Golang的Mutex是值传递还是引用传递?_第1张图片

你好~

你可能感兴趣的:(Golang,golang)