读写锁特点

  • 读+读:通过
  • 读+写:阻塞
  • 写+读:阻塞
  • 写+写:阻塞
type RWMutex struct {
	w           Mutex  // held if there are pending writers
	writerSem   uint32 // 控制获取写锁的信号量
	readerSem   uint32 // 控制获取读锁的信号量
    
	readerCount int32  
	readerWait  int32  
}

func (rw *RWMutex) RLock() {
	if atomic.AddInt32(&rw.readerCount, 1) < 0 {
		runtime_SemacquireMutex(&rw.readerSem, false, 0)
	}
}

func (rw *RWMutex) RUnlock() {
	if r := atomic.AddInt32(&rw.readerCount, -1); r < 0 {
		rw.rUnlockSlow(r)
	}
}

func (rw *RWMutex) rUnlockSlow(r int32) {
	if r+1 == 0 || r+1 == -rwmutexMaxReaders {
		throw("sync: RUnlock of unlocked RWMutex")
	}
	// 每次释放读锁,readerWait 都会减1,直到为0就释放 writerSem 信号量
	if atomic.AddInt32(&rw.readerWait, -1) == 0 {
		runtime_Semrelease(&rw.writerSem, false, 1)
	}
}

func (rw *RWMutex) Lock() {
	rw.w.Lock()
	// r 就是 readerCount 原先的值
    // readerCount 减去一个很大的值,就是表明写锁已经加上了,后续的读锁请求将阻塞
	r := atomic.AddInt32(&rw.readerCount, -rwmutexMaxReaders) + rwmutexMaxReaders
    // 获取了写锁,还要等待所以的读锁全部释放
    // readerWait + r 其实就是还有多少个读锁没有释放,
    //    如果不为0,则需要等待信号量
    //    如果为0,则直接成功,不能等待信号量
	if r != 0 && atomic.AddInt32(&rw.readerWait, r) != 0 {
		runtime_SemacquireMutex(&rw.writerSem, false, 0)
	}
}

func (rw *RWMutex) Unlock() {
	// 将 readerCount 恢复正常值,也就是读锁的个数
	r := atomic.AddInt32(&rw.readerCount, rwmutexMaxReaders)
	if r >= rwmutexMaxReaders {
		throw("sync: Unlock of unlocked RWMutex")
	}
	// 向所以的读锁释放信号量
	for i := 0; i < int(r); i++ {
		runtime_Semrelease(&rw.readerSem, false, 0)
	}
	rw.w.Unlock()
}
readerCount
writerSem

读写锁的关键是,既要操作信号量,但是有可能根本就没有对方,所以又不能盲目的操作,所以先判断一个数量,然后再操作。