美文网首页
go rwmutex 源码

go rwmutex 源码

作者: 上善若水_f6a4 | 来源:发表于2022-04-05 15:49 被阅读0次
    // Copyright 2009 The Go Authors. All rights reserved.
    // Use of this source code is governed by a BSD-style
    // license that can be found in the LICENSE file.
    
    package sync
    
    import (
        "internal/race"
        "sync/atomic"
        "unsafe"
    )
    
    // There is a modified copy of this file in runtime/rwmutex.go.
    // If you make any changes here, see if you should make them there.
    
    // A RWMutex is a reader/writer mutual exclusion lock.
    // The lock can be held by an arbitrary number of readers or a single writer.
    // The zero value for a RWMutex is an unlocked mutex.
    //
    // A RWMutex must not be copied after first use.
    //
    //如果一个goroutine持有一个用于读取的RWMutex,而另一个goroutine可能调用Lock,那么在初始的读锁被释放之前,没有一个goroutine应该能够获得读锁。
    //特别是,这禁止了递归读锁定。这是为了确保锁最终变得可用;阻塞的Lock调用排斥新读取器获取
    // If a goroutine holds a RWMutex for reading and another goroutine might
    // call Lock, no goroutine should expect to be able to acquire a read lock
    // until the initial read lock is released. In particular, this prohibits
    // recursive read locking. This is to ensure that the lock eventually becomes
    // available; a blocked Lock call excludes new readers from acquiring the
    // lock.
    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 表示当写操作被阻塞时等待的读操作个数;
    }
    
    // readerCount 正在执行的读锁个数
    // 加写锁时 atomic.AddInt32(&rw.readerCount, -rwmutexMaxReaders)
    // 加读锁时,进行  atomic.AddInt32(&rw.readerCount, 1) < 0 进行判断, 实现有写锁时,不允许加读锁
    // readerWait 表示写锁等待读锁解锁的数目
    // 写锁在加锁中间过程中,会有一部分读锁加锁,并解锁, 但有可能没有完全解锁
    // 写锁通过 atomic.AddInt32(&rw.readerWait, r) 得到加锁时,这部分没有完全解锁的读锁的数目,如果不为 0,
    // 则写锁进入等待
    
    const rwmutexMaxReaders = 1 << 30
    
    // Happens-before relationships are indicated to the race detector via:
    // - Unlock  -> Lock:  readerSem
    // - Unlock  -> RLock: readerSem
    // - RUnlock -> Lock:  writerSem
    //
    // The methods below temporarily disable handling of race synchronization
    // events in order to provide the more precise model above to the race
    // detector.
    //
    // For example, atomic.AddInt32 in RLock should not appear to provide
    // acquire-release semantics, which would incorrectly synchronize racing
    // readers, thus potentially missing races.
    
    // 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()
        }
        if atomic.AddInt32(&rw.readerCount, 1) < 0 {
            // A writer is pending, wait for it.
            runtime_SemacquireMutex(&rw.readerSem, false, 0)
        }
        if race.Enabled {
            race.Enable()
            race.Acquire(unsafe.Pointer(&rw.readerSem))
        }
    }
    
    // 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()
        }
        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.
        if atomic.AddInt32(&rw.readerWait, -1) == 0 {
            // The last reader unblocks the writer.
            runtime_Semrelease(&rw.writerSem, false, 1)
        }
    }
    
    // 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()
        }
        //指令 1
        //先用 rw.w 加锁
        // First, resolve competition with other writers.
        rw.w.Lock()
    
        // 指令 2
        // 指令1, 指令 2 之间,会有大量读锁加锁解锁,指令2 之后,会有部分读锁未解锁, 此时,r != 0;
        // 如果指令2之后,这部分读锁进行解锁, 会进入 rw.rUnlockSlow
        // rw.rUnlockSlow() 中 atomic.AddInt32(&rw.readerWait, -1) 记录这部分读锁个数
        //
        // Announce to readers there is a pending writer.
        // 通知 readers ,存在正在执行的写协程
        r := atomic.AddInt32(&rw.readerCount, -rwmutexMaxReaders) + rwmutexMaxReaders
    
        // 指令 3
        // Wait for active readers.
        // r != 0 表示有 r 个读锁加锁
        // 如果 i := atomic.AddInt32(&rw.readerWait, r) == 0, 表示这 r 个读锁都已经解锁, 写锁加锁成功
        // 否则表示有 i 个读锁为解锁, 进入等待
        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))
        }
    }
    
    // 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.
        r := atomic.AddInt32(&rw.readerCount, rwmutexMaxReaders)
        if r >= rwmutexMaxReaders {
            race.Enable()
            throw("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()
        if race.Enabled {
            race.Enable()
        }
    }
    
    // RLocker returns a Locker interface that implements
    // the Lock and Unlock methods by calling rw.RLock and rw.RUnlock.
    func (rw *RWMutex) RLocker() Locker {
        return (*rlocker)(rw)
    }
    
    type rlocker RWMutex
    
    func (r *rlocker) Lock()   { (*RWMutex)(r).RLock() }
    func (r *rlocker) Unlock() { (*RWMutex)(r).RUnlock() }
    

    相关文章

      网友评论

          本文标题:go rwmutex 源码

          本文链接:https://www.haomeiwen.com/subject/xtbksrtx.html