feat(sync): rwmutex with 4 mutex
This commit is contained in:
parent
53e48b1f6e
commit
af87eb7b26
10
README.md
Normal file
10
README.md
Normal file
@ -0,0 +1,10 @@
|
|||||||
|
# Coding lab
|
||||||
|
|
||||||
|
> Coding GYM
|
||||||
|
|
||||||
|
## 更新记录
|
||||||
|
|
||||||
|
2023-09-18
|
||||||
|
|
||||||
|
- [ ] Channel 实现读写锁:来自本人参加百度 ACG 面试,彼时对于并发控制的理解颇为纸上谈兵,未能表现实为遗憾。
|
||||||
|
我对用 channel 模拟这个复杂的任务十分有兴趣,因为在这个过程中 channel 将会扮演非常重要的角色(传递信号量),我就是想通过此达到加深理解的作用
|
12
go.mod
Normal file
12
go.mod
Normal 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
12
go.sum
Normal 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
9
sync/rwmutex.go
Normal file
@ -0,0 +1,9 @@
|
|||||||
|
package sync
|
||||||
|
|
||||||
|
import "sync"
|
||||||
|
|
||||||
|
type RWLocker interface {
|
||||||
|
sync.Locker
|
||||||
|
RLock()
|
||||||
|
RUnlock()
|
||||||
|
}
|
72
sync/rwmutex_test.go
Normal file
72
sync/rwmutex_test.go
Normal 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
78
sync/rwmutex_v1.go
Normal 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()
|
||||||
|
}
|
Loading…
Reference in New Issue
Block a user