Skip to content
gqlxj1987's Blog
Go back

Go Lock

Edit page

原文链接

golang部分的锁,主要在sync包里

runtime/sema(信号量)

runtime中的sema.go,信号量的同步功能是作用于goroutine的

type semaRoot struct {
    lock  mutex
    head  *sudog
    tail  *sudog
    nwait uint32 // Number of waiters. Read w/o the lock.
}
// 主要结构就是一个sudog的链表和一个nwait。
// 链表用于存储等待的goroutine,nwait表示在该信号量上等待的goroutine数目。
// lock一个互斥量,是在多线程环境中保护链表的。(但是这个mutex不是sync中的mutex,是sema.go
// 内部使用的一个私有版本)

golang设置了可操作信号量个数的最大量是251,相关操作,还是看链表的操作

sync/atomic

这里原子操作,是保证多个cpu(协程)对同一块内存区域的操作是原子的

// 互斥量加锁操作
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
	}
......

sync/mutex(互斥锁)

sync/mutex.go

// A Mutex must not be copied after first use.
type Mutex struct {
    state int32    // 一个int32整数,用其中的位来表示
    sema  uint32
}

//iota,特殊常量,可以认为是一个可以被编译器修改的常量。
//在每一个const关键字出现时,被重置为0,然后再下一个const出现之前,每出现一次iota,其所代表的数字会自动增加1。
const (
    mutexLocked = 1 << iota //值为1,表示在state中由低向高第1位,意义:锁是否可用,0可用,1不可用
    mutexWoken // 值为2,表示在state中由低向高第2位,意义:mutex是否被唤醒
    mutexWaiterShift = iota //值为2,表示state中统计阻塞在此mutex上goroutine的数目需要位移的偏移量
)

lock流程

简单来说,如果当前goroutine可以加锁,那么调用原子操作使得mutex中的flag设置成已占用达到互斥;如果当前goroutine发现锁已被占用,那么会有条件的循环尝试获取锁,这里是不用信号量去对goroutine进行sleep和wake操作的(尽可能避免开销),如果循环尝试失败,则最后调用原子操作争抢一次,获取不到则还是得调用runtime_Semacquire去判断阻塞goroutine还是继续争用锁。

sync/RWMutex(读写锁)

type RWMutex struct {
	w           Mutex  // held if there are pending writers
	writerSem   uint32 // semaphore for writers to wait for completing readers
	readerSem   uint32 // semaphore for readers to wait for completing writers
	readerCount int32  // number of pending readers
	readerWait  int32  // number of departing readers
}

写锁定

func (rw *RWMutex) Lock() {
	// First, resolve competition with other writers.
	rw.w.Lock()
	// Announce to readers there is a pending writer.
	r := atomic.AddInt32(&rw.readerCount, -rwmutexMaxReaders) + rwmutexMaxReaders
	// Wait for active readers.
	if r != 0 && atomic.AddInt32(&rw.readerWait, r) != 0 {
		runtime_Semacquire(&rw.writerSem)
	}
}

Edit page
Share this post on:

Previous Post
2018碎碎念
Next Post
Building distributed log from scratch With Storage Mechanics