GOのRWMutexに対する自分の理解について話します


RWMutexのコアはやはりMutexに基づいているので、Mutexを知りたいなら前に書いたMutexの文章を見てもいいです.
RWMutexの特性は同時読み取りをサポートすることである.読み書きが少ないシーンに適しています.

RWMutexの定義

type RWMutex struct {
    w           Mutex  //  
    writerSem   uint32 //  
    readerSem   uint32 //  
    readerCount int32  //  goroutine 
    readerWait  int32  //  , goroutine 
}

const rwmutexMaxReaders = 1 << 30

RWMutex.Lock()

func (rw *RWMutex) Lock() {
    //  Mutex Lock 
    rw.w.Lock()
    
    //  readerCount , 
    // r  goroutine  
    r := atomic.AddInt32(&rw.readerCount, -rwmutexMaxReaders) + rwmutexMaxReaders
    
    //  goroutine
    //  r readerWait
    if r != 0 && atomic.AddInt32(&rw.readerWait, r) != 0 {
    
        //  goroutine , 
        runtime_SemacquireMutex(&rw.writerSem, false, 0)
    }
}

RWMutex.Unlock()

func (rw *RWMutex) Unlock() {

    //  readerCount , 
    r := atomic.AddInt32(&rw.readerCount, rwmutexMaxReaders)
    ...
    
    //  goroutine
    for i := 0; i < int(r); i++ {
        runtime_Semrelease(&rw.readerSem, false, 0)
    }
    
    //  , 
    rw.w.Unlock()
}

RWMutex.RLock()

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

RWMutex.RUnlock()

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

func (rw *RWMutex) rUnlockSlow(r int32) {
    ...
    
    // readerWait - 1
    //  goroutine 
    if atomic.AddInt32(&rw.readerWait, -1) == 0 {
    
        //  
        runtime_Semrelease(&rw.writerSem, false, 1)
    }
}

まとめ


リードロックを取得するプロセス
  • readerCount + 1
  • readerCount<0で、書き込みロックによってブロックされているか否かを判断する、そうすると、現在goroutineは休眠
  • に入る.
    リードロックを解除するプロセス
  • readerCount - 1
  • はreaderCount<0で書き込みロック
  • があるか否かを判断する.
  • 書き込みロックがない場合は、
  • に戻ります.
  • 書き込みロックがあればrUnlockSlowメソッドを呼び出し、readerWait-1
  • readerWait==0の場合、現在のgoroutineが書き込みロック待ちの最後の読み取りロックgoroutineであることを示し、書き込みロックgoroutine
  • を起動する必要がある
    書き込みロックの取得プロセス
  • まず反発ロック
  • を取得する.
  • readerCount-rwmutexMaxReaders、後続の読み取り操作はすべて
  • をブロックします.
  • readerWait+=readerCountは、現在実行中の読み取り操作の数をreaderWait上の
  • に加算する
  • readerWait!=0は、現在他のgoroutineがリードロックを持っていることを示し、現在goroutineは睡眠に入り、目覚ましを待つ
  • 書き込みロックプロセスの解放
  • readerCount+rwmutexMaxReaders、後続のリードロックは
  • をブロックしません.
  • readerCountは、以前に書き込みロックによってブロックされたリードロックgoroutine個数を表し、readerCount個のリードロックgoroutine
  • を起動する.
  • 最後に反発ロック
  • を解放する.
    最後に
    RWMutexはMutexに対してリードロックの制御を増やし、コードロジックの複雑さについては、RWMutexはMutexよりもずっと簡単で、Mutexの流れに慣れていれば、すぐにRWMutexの原理を把握することができます