Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

[Golang] sync.Mutex 实现原理 #21

Open
wisecsj opened this issue Mar 10, 2019 · 2 comments
Open

[Golang] sync.Mutex 实现原理 #21

wisecsj opened this issue Mar 10, 2019 · 2 comments

Comments

@wisecsj
Copy link
Owner

wisecsj commented Mar 10, 2019

先埋个坑,更细致到代码的理解以后再填

// A Mutex is a mutual exclusion lock.
// The zero value for a Mutex is an unlocked mutex.
//
// A Mutex must not be copied after first use.
type Mutex struct {
	state int32
	sema  uint32
}
const (
	mutexLocked = 1 << iota // mutex is locked
	mutexWoken
	mutexStarving
	mutexWaiterShift = iota
	starvationThresholdNs = 1e6
)
@wisecsj
Copy link
Owner Author

wisecsj commented Mar 10, 2019

Mutex是互斥锁,不能嵌套,可以一个goroutine Lock,另一个Unlock

state是一个32位整型,譬如:00000000|00000000|00000000|0000cba
a代表mutex是否已经locked,b代表mutexWoken,c代表mutexStarving,后面的位代表Waiter的数量

进行**Lock()**的流程大体如下:

首先利用CAS原子操作判断mutex是否lock,如果没有,则直接置state为1然后返回。

	if atomic.CompareAndSwapInt32(&m.state, 0, mutexLocked) {
		if race.Enabled {
			race.Acquire(unsafe.Pointer(m))
		}
		return
	}

(先不考虑mutexStarving影响)如果mutex locked,那么mutex会先自旋一段时间:不主动让出cpu时间片,适用于锁可以短时间获取的情况。因为这样的话,不用去获取semaphore,和之后goroutine上下文切换带来的开销。

那么自旋时间由什么决定,由 runtime_canSpin(iter int) :传递过来的iter大等于4或者cpu核数小等于1,最大逻辑处理器大于1,至少有个本地的P队列,并且本地的P队列可运行G队列为空.

如果还没有获得锁,那么就会执行 runtime_SemacquireMutex ,然后将goroutine作为一个waiter放置到waiter queue中。

mutexStarving :它是golang为了优化mutex而出现的,当waiter为了获取锁而等待的时间超过 starvationThresholdNs (默认为1ms),那么当放入queue的时候,就是置于头部,从而解决饥饿问题-----LIFO

@wisecsj
Copy link
Owner Author

wisecsj commented Mar 10, 2019

有的时候,我们或许不仅要学习代码,更应学会代码背后的思想。所以,或许我们看一个项目的源代码,从最初版本看会更容易理解、看到本质。因为之后的版本往往会包含大量的优化细节实现。


Semaphores in Plan 9

这份pdf之后得好好看看,是很好的了解 golang runtime semaphore 实现的资料

Reference

How are mutexes implemented in Go?

release-branch.go1/src/pkg/sync/mutex.go

golang互斥锁内部实现

@wisecsj wisecsj pinned this issue Mar 10, 2019
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

No branches or pull requests

1 participant