go的mutex如何实现?

为什么80%的码农都做不了架构师?>>>   hot3.png

已知

c++中多线程的mutex,是通过futex来实现原子操作+线程唤醒的,然后再加上memory barrier(内存序)来保证内存可见性的。即:

mutex = futex + memory barrier = atomic + thread schedule + memory barrier

详情可参见这篇博客:pthread_mutex_lock实现原理

新问题

go中多协程的mutex,如何实现?

猜测

goroutine mutex = atomic + goroutine schedule + memory barrier

即有3个条件:

  1. 有原子操作
  2. 有goroutine的调度
  3. 有内存屏障

验证

sync/mutex.go#L69

// 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
	}
	// Slow path (outlined so that the fast path can be inlined)
	m.lockSlow() // 这里是原子操作失败,可能会“阻塞”的场景。调用了runtime_SemacquireMutex
}

runtime/race.go#L28

// RaceAcquire/RaceRelease/RaceReleaseMerge establish happens-before relations
// between goroutines. These inform the race detector about actual synchronization
// that it can't see for some reason (e.g. synchronization within RaceDisable/RaceEnable
// sections of code).
// RaceAcquire establishes a happens-before relation with the preceding
// RaceReleaseMerge on addr up to and including the last RaceRelease on addr.
// In terms of the C memory model (C11 §5.1.2.4, §7.17.3),
// RaceAcquire is equivalent to atomic_load(memory_order_acquire). // 这里是内存屏障
func RaceAcquire(addr unsafe.Pointer) {
	raceacquire(addr)
}

sync/runtime.go#L16

// Semrelease atomically increments *s and notifies a waiting goroutine
// if one is blocked in Semacquire.
// It is intended as a simple wakeup primitive for use by the synchronization
// library and should not be used directly.
// If handoff is true, pass count directly to the first waiter.
// skipframes is the number of frames to omit during tracing, counting from
// runtime_Semrelease's caller.
func runtime_Semrelease(s *uint32, handoff bool, skipframes int) // 这里是协程调度

到此结束。

转载于:https://my.oschina.net/chuqq/blog/3023741

你可能感兴趣的:(go的mutex如何实现?)