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