zoukankan      html  css  js  c++  java
  • go源码阅读

    相比于Mutex来说,RWMutex锁的粒度更细,使用RWMutex可以并发读,但是不能并发读写,或者写写。

    1. 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
    // 当前执行读的goroutine的数量 readerCount int32 // number of pending readers
    // 获取写锁时需要等待的读锁释放数量 readerWait int32 // number of departing readers } const rwmutexMaxReaders = 1 << 30

      

     2. 加读锁 RLock()

    // RLock locks rw for reading.
    //
    // It should not be used for recursive read locking; a blocked Lock
    // call excludes new readers from acquiring the lock. See the
    // documentation on the RWMutex type.
    func (rw *RWMutex) RLock() {
    	if race.Enabled {
    		_ = rw.w.state
    		race.Disable()
    	}
    // 调用这个原子方法,原子加 1
    // 如果写锁已经被获取,那么 readercount在 -rwmutexMaxReaders和0之间,这是将请求获取 RLock的 goroutine的挂起
    // 如果写锁没有被获取,那么 readercount大于 0,获取读锁 ,不阻塞。
    // 通过 readerCount判断读锁与写锁互斥,如果存在写锁则挂起goroutine,多个读锁可以并行 if atomic.AddInt32(&rw.readerCount, 1) < 0 { // A writer is pending, wait for it.
    // 这时休眠这个goroutine,等待被唤醒 runtime_SemacquireMutex(&rw.readerSem, false, 0) } if race.Enabled { race.Enable() race.Acquire(unsafe.Pointer(&rw.readerSem)) } }

    3. 解读锁

    // 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 race.Enabled {
    		_ = rw.w.state
    		race.ReleaseMerge(unsafe.Pointer(&rw.writerSem))
    		race.Disable()
    	}
    // 正在读的goroutine数减1
    // 如果小于0,说明 1. 当前有正在等待获取写锁的goroutine或者多次解锁,进入慢速通道
    if r := atomic.AddInt32(&rw.readerCount, -1); r < 0 { // Outlined slow-path to allow the fast-path to be inlined rw.rUnlockSlow(r) } if race.Enabled { race.Enable() } }

    func (rw *RWMutex) rUnlockSlow(r int32) {
    // 如果多次解锁,则抛出异常
    if r+1 == 0 || r+1 == -rwmutexMaxReaders {
    race.Enable()
    throw("sync: RUnlock of unlocked RWMutex")
    }
    // A writer is pending.
    // 如果有正在等待获取写锁的goroutine, 并且当前的read goroutine是最后一个持有读锁的goroutine, 那么通过信号量唤醒等待获取写锁的goroutine.
    if atomic.AddInt32(&rw.readerWait, -1) == 0 {
    // The last reader unblocks the writer.
    runtime_Semrelease(&rw.writerSem, false, 1)
    }
    }

      

    4. 加写锁

    // 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() {
    	if race.Enabled {
    		_ = rw.w.state
    		race.Disable()
    	}
    	// First, resolve competition with other writers.
    // 首先调用互斥锁的 Lock,获取到互斥锁 rw.w.Lock() // Announce to readers there is a pending writer.
    // 阻塞后续的读操作 r := atomic.AddInt32(&rw.readerCount, -rwmutexMaxReaders) + rwmutexMaxReaders // Wait for active readers.
    // 如果计算之后仍有其他goroutine获取读锁,,那么调用 runtime_SemacquireMutex 休眠当前的goroutine直到所有的读操作完成 if r != 0 && atomic.AddInt32(&rw.readerWait, r) != 0 { runtime_SemacquireMutex(&rw.writerSem, false, 0) } if race.Enabled { race.Enable() race.Acquire(unsafe.Pointer(&rw.readerSem)) race.Acquire(unsafe.Pointer(&rw.writerSem)) } }

    5. 解写锁

    // 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() {
    	if race.Enabled {
    		_ = rw.w.state
    		race.Release(unsafe.Pointer(&rw.readerSem))
    		race.Disable()
    	}
    
    	// Announce to readers there is no active writer.
    // 将 readerCount 恢复 r := atomic.AddInt32(&rw.readerCount, rwmutexMaxReaders) if r >= rwmutexMaxReaders { race.Enable() throw("sync: Unlock of unlocked RWMutex") } // Unblock blocked readers, if any.
    // 循环唤醒等待获取读锁的 goroutine for i := 0; i < int(r); i++ { runtime_Semrelease(&rw.readerSem, false, 0) } // Allow other writers to proceed. rw.w.Unlock() if race.Enabled { race.Enable() } }

      

  • 相关阅读:
    java接口对入参的判断校验
    sqlyog使用技巧
    mysql 数据库的表中复制一条数据并添加到该表中
    union all ,union 注意事项,查询结果集中的字段名称顺序必须一致
    IDEA连接mysq数据库,其实很简单
    git版本回退、git远程分支管理、git本地分支管理、git生产代码bug修复
    Vue上拉加载下拉刷新---vue-easyrefresh
    Flutter上拉加载下拉刷新---flutter_easyrefresh
    vue-cli webpack多Html页面的配置(附框架vue-webpack-multipage实例)
    Qt使用镜像源快速安装与更新
  • 原文地址:https://www.cnblogs.com/juanmaofeifei/p/14715264.html
Copyright © 2011-2022 走看看