GoCollections/concurrent/ReentrantRWLock.go
2022-03-23 14:28:41 +08:00

72 lines
1.2 KiB
Go

package concurrent
import (
"fmt"
"github.com/tursom/GoCollections/exceptions"
"sync"
)
type ReentrantRWLock struct {
lock sync.Mutex
rlock sync.RWMutex
cond sync.Cond
recursion int32
host int64
}
func NewReentrantRWLock() *ReentrantRWLock {
res := &ReentrantRWLock{
recursion: 0,
host: 0,
}
res.cond = *sync.NewCond(&res.lock)
return res
}
func (rt *ReentrantRWLock) Lock() {
id := GetGoroutineID()
rt.lock.Lock()
defer rt.lock.Unlock()
if rt.host == id {
rt.recursion++
return
}
for rt.recursion != 0 {
rt.cond.Wait()
}
rt.host = id
rt.recursion = 1
rt.rlock.Lock()
}
func (rt *ReentrantRWLock) Unlock() {
rt.lock.Lock()
defer rt.lock.Unlock()
if rt.recursion == 0 || rt.host != GetGoroutineID() {
panic(exceptions.NewWrongCallHostException(fmt.Sprintf("the wrong call host: (%d); current_id: %d; recursion: %d", rt.host, GetGoroutineID(), rt.recursion)))
}
rt.recursion--
if rt.recursion == 0 {
rt.rlock.Unlock()
rt.cond.Signal()
}
}
func (rt *ReentrantRWLock) RLock() {
if rt.host == GetGoroutineID() {
return
}
rt.rlock.RLock()
}
func (rt *ReentrantRWLock) RUnlock() {
if rt.host == GetGoroutineID() {
return
}
rt.rlock.RUnlock()
}