网站备案 个人,网站建设的分阶段步骤,潍坊网站建设 世纪环球16楼,潍坊网站建设选聚搜网络好go读写锁的实现原理 
1、RWMutex读写锁的概念 
读写锁也就是我们所使用的RWMutex#xff0c;其实是对于go本身的mutex做的一个拓展#xff0c;当一个goroutine获得了读锁后#xff0c;其他goroutine同样可以获得读锁#xff0c;但是不能获得写锁。相反#xff0c;当一个go…go读写锁的实现原理 
1、RWMutex读写锁的概念 
读写锁也就是我们所使用的RWMutex其实是对于go本身的mutex做的一个拓展当一个goroutine获得了读锁后其他goroutine同样可以获得读锁但是不能获得写锁。相反当一个goroutine获得了写锁其他goroutine既不能读也不能写互斥的概念。 
2、使用场景 
适用于读多写少的情况 
3、底层实现 
读写锁实现的结构体位于src下的sync包下的rwmutex.go文件中 
type RWMutex struct {w           Mutex  // held if there are pending writerswriterSem   uint32 // semaphore for writers to wait for completing readersreaderSem   uint32 // semaphore for readers to wait for completing writersreaderCount int32  // number of pending readersreaderWait  int32  // number of departing readers
}	w字段代表着复用了互斥锁 
writerSem代表写信号量用于写等待读 
readerSem代表读信号量用于读等待写 
readerCount代表当前执行读的goroutine数量 
readerWait代表被阻塞的准备读的goroutine的数量 
4、读锁的实现 
加读锁 
func (rw *RWMutex) RLock() {if atomic.AddInt32(rw.readerCount, 1)  0 {// A writer is pending, wait for it.runtime_SemacquireMutex(rw.readerSem, false, 0)}
}首先看这个if方法为什么要判断小于0呢 
atomic.AddInt32(rw.readerCount, 1)  0调用的这个原子方法目的就是当goroutine加读锁的时候读锁数量1如果返回的数量是负数那么就代表了当前有其他写锁这个时候就掉用runtime_SemacquireMutex方法休眠当前goroutinereaderSem就记录者这个goroutine。所以要判断是否小于0 
释放读锁 
// RUnlock undoes a single RLock call;
// it does not affect other simultaneous readers.
// It is a run-time error if rw is not locked for reading
// on entry to RUnlock.
func (rw *RWMutex) RUnlock() {if r : atomic.AddInt32(rw.readerCount, -1); r  0 {// Outlined slow-path to allow the fast-path to be inlinedrw.rUnlockSlow(r)}
}释放读锁的时候就是对readerCount读数量-1即可如果返回值小于0就代表着当前有写的操作这个时候就会调用rUnlockSlow进入慢速通道 
什么是慢速通道 
func (rw *RWMutex) rUnlockSlow(r int32) {// A writer is pending.if atomic.AddInt32(rw.readerWait, -1)  0 {// The last reader unblocks the writer.runtime_Semrelease(rw.writerSem, false, 1)}
}被阻塞的准备读的goroutine数量-1如果readerWait为0就表示当前没有goroutine正在准备读这个时候去唤醒写操作 
5、写锁的实现 
加写锁 
const rwmutexMaxReaders  1  30
// Lock locks rw for writing.
// If the lock is already locked for reading or writing,
// Lock blocks until the lock is available.
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_SemacquireMutex(rw.writerSem, false, 0)}
}写锁的调用就是调用互斥锁w的lock如果计算之后还是有其他goroutine持有读锁那么就调用runtime_SemacquireMutex休眠当前的goroutine等待所有的读操作完成 atomic.AddInt32(rw.readerCount, -rwmutexMaxReaders)  rwmutexMaxReaders这个操作目的是防止后面的goroutine拿到读锁阻塞读的作用。 
释放写锁 
// Unlock unlocks rw for writing. It is a run-time error if rw is
// not locked for writing on entry to Unlock.
//
// As with Mutexes, a locked RWMutex is not associated with a particular
// goroutine. One goroutine may RLock (Lock) a RWMutex and then
// arrange for another goroutine to RUnlock (Unlock) it.
func (rw *RWMutex) Unlock() {// Announce to readers there is no active writer.r : atomic.AddInt32(rw.readerCount, rwmutexMaxReaders)if r  rwmutexMaxReaders {race.Enable()fatal(sync: Unlock of unlocked RWMutex)}// Unblock blocked readers, if any.for i : 0; i  int(r); i {runtime_Semrelease(rw.readerSem, false, 0)}// Allow other writers to proceed.rw.w.Unlock()
}当释放写锁的时候首先会通过atomic.AddInt32(rw.readerCount, rwmutexMaxReaders)恢复之前的写入的很大的那个负数然后看当前有多少个读操作在等待循环唤醒等待读的goroutine 
注意go中的锁不支持可重入锁若想实现可自定义实现 
6、总结 
读写锁区分读锁和写锁而普通的互斥锁不区分读写锁主要应用在读多写少的场景既保证了并发读的执行效率又保证了线程之间的安全。