github.com/songzhibin97/go-baseutils@v0.0.2-0.20240302024150-487d8ce9c082/sys/syncx/rwmutex.go (about)

     1  package syncx
     2  
     3  import (
     4  	"runtime"
     5  	"sync"
     6  	"unsafe"
     7  
     8  	"github.com/songzhibin97/go-baseutils/internal/runtimex"
     9  	"github.com/songzhibin97/go-baseutils/sys/cpu"
    10  )
    11  
    12  const (
    13  	cacheLineSize = unsafe.Sizeof(cpu.CacheLinePad{})
    14  )
    15  
    16  var (
    17  	shardsLen int
    18  )
    19  
    20  // RWMutex is a p-shard mutex, which has better performance when there's much more read than write.
    21  type RWMutex []rwMutexShard
    22  
    23  type rwMutexShard struct {
    24  	sync.RWMutex
    25  	_pad [cacheLineSize - unsafe.Sizeof(sync.RWMutex{})]byte
    26  }
    27  
    28  func init() {
    29  	shardsLen = runtime.GOMAXPROCS(0)
    30  }
    31  
    32  // NewRWMutex creates a new RWMutex.
    33  func NewRWMutex() RWMutex {
    34  	return make([]rwMutexShard, shardsLen)
    35  }
    36  
    37  func (m RWMutex) Lock() {
    38  	for shard := range m {
    39  		m[shard].Lock()
    40  	}
    41  }
    42  
    43  func (m RWMutex) Unlock() {
    44  	for shard := range m {
    45  		m[shard].Unlock()
    46  	}
    47  }
    48  
    49  func (m RWMutex) RLocker() sync.Locker {
    50  	return m[runtimex.Pid()%shardsLen].RWMutex.RLocker()
    51  }