mirror of
https://github.com/tursom/GoCollections.git
synced 2025-03-15 10:10:13 +08:00
add ReentrantLock
This commit is contained in:
parent
ca060c0304
commit
3057483900
@ -6,9 +6,20 @@ type (
|
||||
Unlock()
|
||||
}
|
||||
RWLock interface {
|
||||
Lock()
|
||||
Unlock()
|
||||
Lock
|
||||
RLock()
|
||||
RUnlock()
|
||||
}
|
||||
)
|
||||
|
||||
func WithLock[R any](lock Lock, f func() R) R {
|
||||
lock.Lock()
|
||||
defer lock.Unlock()
|
||||
return f()
|
||||
}
|
||||
|
||||
func WithRLock[R any](lock RWLock, f func() R) R {
|
||||
lock.RLock()
|
||||
defer lock.RUnlock()
|
||||
return f()
|
||||
}
|
||||
|
@ -1,26 +1,54 @@
|
||||
package concurrent
|
||||
|
||||
import "sync"
|
||||
import (
|
||||
"fmt"
|
||||
"github.com/tursom/GoCollections/exceptions"
|
||||
"sync"
|
||||
)
|
||||
|
||||
type ReentrantLock struct {
|
||||
sync.Mutex
|
||||
cnt int32
|
||||
lock sync.Mutex
|
||||
cond sync.Cond
|
||||
recursion int32
|
||||
host int64
|
||||
}
|
||||
|
||||
func (l *ReentrantLock) Lock() {
|
||||
defer func() {
|
||||
r := recover()
|
||||
if r != nil {
|
||||
l.cnt++
|
||||
}
|
||||
}()
|
||||
|
||||
l.Mutex.Lock()
|
||||
func NewReentrantLock() *ReentrantLock {
|
||||
res := &ReentrantLock{
|
||||
recursion: 0,
|
||||
host: 0,
|
||||
}
|
||||
res.cond = *sync.NewCond(&res.lock)
|
||||
return res
|
||||
}
|
||||
|
||||
func (l *ReentrantLock) Unlock() {
|
||||
l.cnt--
|
||||
if l.cnt == 0 {
|
||||
l.Mutex.Unlock()
|
||||
func (rt *ReentrantLock) 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
|
||||
}
|
||||
|
||||
func (rt *ReentrantLock) 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.cond.Signal()
|
||||
}
|
||||
}
|
||||
|
71
concurrent/ReentrantRWLock.go
Normal file
71
concurrent/ReentrantRWLock.go
Normal file
@ -0,0 +1,71 @@
|
||||
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()
|
||||
}
|
27
concurrent/ReentrantRWLock_test.go
Normal file
27
concurrent/ReentrantRWLock_test.go
Normal file
@ -0,0 +1,27 @@
|
||||
package concurrent
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"testing"
|
||||
"time"
|
||||
)
|
||||
|
||||
func TestReentrantRWLock_RLock(t *testing.T) {
|
||||
lock := NewReentrantRWLock()
|
||||
lock.Lock()
|
||||
defer lock.Unlock()
|
||||
|
||||
go func() {
|
||||
lock.Lock()
|
||||
defer lock.Unlock()
|
||||
fmt.Println("get lock")
|
||||
}()
|
||||
time.Sleep(time.Second)
|
||||
lock.Lock()
|
||||
defer lock.Unlock()
|
||||
lock.RLock()
|
||||
defer lock.RUnlock()
|
||||
lock.RLock()
|
||||
defer lock.RUnlock()
|
||||
fmt.Println("release lock")
|
||||
}
|
7
concurrent/Util.go
Normal file
7
concurrent/Util.go
Normal file
@ -0,0 +1,7 @@
|
||||
package concurrent
|
||||
|
||||
import "github.com/petermattis/goid"
|
||||
|
||||
func GetGoroutineID() int64 {
|
||||
return goid.Get()
|
||||
}
|
11
exceptions/WrongCallHostException.go
Normal file
11
exceptions/WrongCallHostException.go
Normal file
@ -0,0 +1,11 @@
|
||||
package exceptions
|
||||
|
||||
type WrongCallHostException struct {
|
||||
RuntimeException
|
||||
}
|
||||
|
||||
func NewWrongCallHostException(message string) WrongCallHostException {
|
||||
return WrongCallHostException{
|
||||
NewRuntimeException(nil, message, nil),
|
||||
}
|
||||
}
|
Loading…
Reference in New Issue
Block a user