feat(sync): rwmutex with 4 mutex

This commit is contained in:
🐟 2023-09-18 17:38:04 +08:00
parent 53e48b1f6e
commit af87eb7b26
6 changed files with 193 additions and 0 deletions

10
README.md Normal file
View File

@ -0,0 +1,10 @@
# Coding lab
> Coding GYM
## 更新记录
2023-09-18
- [ ] Channel 实现读写锁:来自本人参加百度 ACG 面试,彼时对于并发控制的理解颇为纸上谈兵,未能表现实为遗憾。
我对用 channel 模拟这个复杂的任务十分有兴趣,因为在这个过程中 channel 将会扮演非常重要的角色(传递信号量),我就是想通过此达到加深理解的作用

12
go.mod Normal file
View File

@ -0,0 +1,12 @@
module lab.evlic.cn/go/coding-lab
go 1.21.0
require github.com/smartystreets/goconvey v1.8.1
require (
github.com/gopherjs/gopherjs v1.17.2 // indirect
github.com/jtolds/gls v4.20.0+incompatible // indirect
github.com/smarty/assertions v1.15.0 // indirect
lab.evlic.cn/go/pkg v1.0.0 // indirect
)

12
go.sum Normal file
View File

@ -0,0 +1,12 @@
github.com/gopherjs/gopherjs v1.17.2 h1:fQnZVsXk8uxXIStYb0N4bGk7jeyTalG/wsZjQ25dO0g=
github.com/gopherjs/gopherjs v1.17.2/go.mod h1:pRRIvn/QzFLrKfvEz3qUuEhtE/zLCWfreZ6J5gM2i+k=
github.com/jtolds/gls v4.20.0+incompatible h1:xdiiI2gbIgH/gLH7ADydsJ1uDOEzR8yvV7C0MuV77Wo=
github.com/jtolds/gls v4.20.0+incompatible/go.mod h1:QJZ7F/aHp+rZTRtaJ1ow/lLfFfVYBRgL+9YlvaHOwJU=
github.com/smarty/assertions v1.15.0 h1:cR//PqUBUiQRakZWqBiFFQ9wb8emQGDb0HeGdqGByCY=
github.com/smarty/assertions v1.15.0/go.mod h1:yABtdzeQs6l1brC900WlRNwj6ZR55d7B+E8C6HtKdec=
github.com/smartystreets/goconvey v1.8.1 h1:qGjIddxOk4grTu9JPOU31tVfq3cNdBlNa5sSznIX1xY=
github.com/smartystreets/goconvey v1.8.1/go.mod h1:+/u4qLyY6x1jReYOp7GOM2FSt8aP9CzCZL03bI28W60=
lab.evlic.cn/go/pkg v0.0.0-20230918075852-9ca9becf0967 h1:Jk4Io04lRwRtTo56GDahstQQksv3ZzglK6QxUarpakY=
lab.evlic.cn/go/pkg v0.0.0-20230918075852-9ca9becf0967/go.mod h1:hvaZsvZvj+ly1Fz59x/d/HyyTAL33T44yTjQx/T/SZ8=
lab.evlic.cn/go/pkg v1.0.0 h1:IuuGjOLTEG9wAWsm4jXh2L7SN6vCJahHOUGAjZ18uno=
lab.evlic.cn/go/pkg v1.0.0/go.mod h1:hvaZsvZvj+ly1Fz59x/d/HyyTAL33T44yTjQx/T/SZ8=

9
sync/rwmutex.go Normal file
View File

@ -0,0 +1,9 @@
package sync
import "sync"
type RWLocker interface {
sync.Locker
RLock()
RUnlock()
}

72
sync/rwmutex_test.go Normal file
View File

@ -0,0 +1,72 @@
package sync
import (
"sync"
"testing"
"time"
. "github.com/smartystreets/goconvey/convey"
)
func newSyncRWMutex() RWLocker {
return &sync.RWMutex{}
}
func TestChannelRWMutex(t *testing.T) {
testCase := map[string]func() RWLocker{
"go-src": newSyncRWMutex,
"rw-mutex_v1": NewRWMutexV1,
}
Convey("rw_mutex", t, func() {
for key, newRWMutexFunc := range testCase {
Convey("rw_mutex_"+key, func() {
rwLock := newRWMutexFunc()
var wg sync.WaitGroup
// 读操作示例
for i := 0; i < 5; i++ {
wg.Add(1)
go func(id int) {
defer wg.Done()
rwLock.RLock()
defer rwLock.RUnlock()
//fmt.Printf("Reader %d is reading...\n", id)
time.Sleep(time.Millisecond * 500)
}(i)
}
// 写操作示例
for i := 0; i < 2; i++ {
wg.Add(1)
go func(id int) {
defer wg.Done()
rwLock.Lock()
defer rwLock.Unlock()
//fmt.Printf("Writer %d is writing...\n", id)
time.Sleep(time.Millisecond * 1000)
}(i)
}
// 等待所有协程完成
wg.Wait()
})
}
})
}
func BenchmarkChannelRWMutex(b *testing.B) {
rwLock := NewRWMutexV1()
var wg sync.WaitGroup
b.ResetTimer()
for i := 0; i < b.N; i++ {
wg.Add(1)
go func() {
defer wg.Done()
rwLock.RLock()
defer rwLock.RUnlock()
}()
}
wg.Wait()
}

78
sync/rwmutex_v1.go Normal file
View File

@ -0,0 +1,78 @@
package sync
import (
"sync"
)
/*
ChannelRWMutexV1
使用四把锁
*/
type ChannelRWMutexV1 struct {
mu sync.Mutex // 互斥锁
rm sync.Mutex // 读等待锁
wm sync.Mutex // 写等待锁
cmu sync.Mutex // 计数锁
rn int // 读等待
wn int // 写等待
}
func NewRWMutexV1() RWLocker {
return &ChannelRWMutexV1{}
}
func (rw *ChannelRWMutexV1) RLock() {
rw.cmu.Lock()
if rw.wn > 0 {
rw.cmu.Unlock()
rw.wm.Lock()
rw.wm.Unlock()
} else {
defer rw.cmu.Unlock()
}
rw.rn++
if rw.rn == 1 {
rw.wm.Lock()
}
}
func (rw *ChannelRWMutexV1) RUnlock() {
rw.cmu.Lock()
defer rw.cmu.Unlock()
rw.rn--
if rw.rn == 0 {
rw.wm.Unlock()
}
}
func (rw *ChannelRWMutexV1) Lock() {
rw.cmu.Lock()
if rw.rn > 0 {
rw.cmu.Unlock()
rw.wm.Lock()
rw.wm.Unlock()
} else {
defer rw.cmu.Unlock()
}
rw.wn++
if rw.wn == 1 {
rw.rm.Lock()
}
rw.mu.Lock()
}
func (rw *ChannelRWMutexV1) Unlock() {
rw.cmu.Lock()
defer rw.cmu.Unlock()
rw.wn--
if rw.wn == 0 {
rw.rm.Unlock()
}
rw.mu.Unlock()
}