diff --git a/cleanup_guard/cleanup_guard.go b/cleanup_guard/cleanup_guard.go index 50fa8ec..63334c2 100644 --- a/cleanup_guard/cleanup_guard.go +++ b/cleanup_guard/cleanup_guard.go @@ -20,5 +20,11 @@ func (g *CleanupGuard) Enable() { } func (g *CleanupGuard) Run() { - g.fn() + g.mutex.Lock() + enabled := g.enable + g.mutex.Unlock() + + if enabled { + g.fn() + } } diff --git a/collections/linked_list.go b/collections/linked_list.go index 7068116..6bda86e 100644 --- a/collections/linked_list.go +++ b/collections/linked_list.go @@ -95,20 +95,22 @@ func (l *LinkedList[T]) PushTail() { } func (l *LinkedList[T]) Exist(v T) bool { - ret := false - l.ForEach(func(t T) bool { - // if t == v { - // ret = true - // return true - // } + l.mu.RLock() + defer l.mu.RUnlock() - return false - }) + for current := l.head; current != nil; current = current.next { + if any(current.item) == any(v) { + return true + } + } - return ret + return false } func (l *LinkedList[T]) RemoveAt(index int) { + l.mu.Lock() + defer l.mu.Unlock() + var i int var prev *linkedNode[T] @@ -130,15 +132,22 @@ func (l *LinkedList[T]) RemoveAt(index int) { } func (l *LinkedList[T]) IsEmpty() bool { + l.mu.RLock() + defer l.mu.RUnlock() return l.size == 0 } func (l *LinkedList[T]) Size() int { + l.mu.RLock() + defer l.mu.RUnlock() return l.size } func (l *LinkedList[T]) GetAt(i int) T { - if i <= l.Size() { + l.mu.RLock() + defer l.mu.RUnlock() + + if i < l.size { var n int for current := l.head; current != nil; current = current.next { if n == i { @@ -152,6 +161,9 @@ func (l *LinkedList[T]) GetAt(i int) T { } func (l *LinkedList[T]) ForEach(fn func(T) bool) { + l.mu.RLock() + defer l.mu.RUnlock() + for current := l.head; current != nil; current = current.next { if fn(current.item) { break @@ -160,26 +172,42 @@ func (l *LinkedList[T]) ForEach(fn func(T) bool) { } func (l *LinkedList[T]) Clear() { + l.mu.Lock() + defer l.mu.Unlock() + l.head = nil l.tail = nil l.size = 0 } func (l *LinkedList[T]) ToList() []T { + l.mu.RLock() + defer l.mu.RUnlock() + ret := make([]T, 0, l.size) - l.ForEach(func(t T) bool { - ret = append(ret, t) - return false - }) + for current := l.head; current != nil; current = current.next { + ret = append(ret, current.item) + } return ret } func (l *LinkedList[T]) String() string { - return fmt.Sprint(l.ToList()) + l.mu.RLock() + defer l.mu.RUnlock() + + ret := make([]T, 0, l.size) + for current := l.head; current != nil; current = current.next { + ret = append(ret, current.item) + } + + return fmt.Sprint(ret) } func (l *LinkedList[T]) remove(n *linkedNode[T]) { + l.mu.Lock() + defer l.mu.Unlock() + n.next = nil l.size-- } diff --git a/collections/list/linked_list.go b/collections/list/linked_list.go index 0652164..a978212 100644 --- a/collections/list/linked_list.go +++ b/collections/list/linked_list.go @@ -40,21 +40,38 @@ func (l *LinkedList[T]) PushFront(v T) *LinkedList[T] { } func (l *LinkedList[T]) FrontNode() *LinkedNode[T] { + l.mu.RLock() + defer l.mu.RUnlock() + return l.front } func (l *LinkedList[T]) Front() T { - return l.FrontNode().Value + l.mu.RLock() + defer l.mu.RUnlock() + + if l.size == 0 { + panic(ErrorOutOffRange) + } + + return l.front.Value } func (l *LinkedList[T]) BackNode() *LinkedNode[T] { + l.mu.RLock() + defer l.mu.RUnlock() + return l.tail } func (l *LinkedList[T]) Back() T { + l.mu.RLock() + defer l.mu.RUnlock() + if l.size == 0 { panic(ErrorOutOffRange) } + return l.tail.Value } @@ -70,7 +87,10 @@ func (l *LinkedList[T]) ForEach(fn func(T) bool) { } func (l *LinkedList[T]) GetAt(i int) T { - if i <= l.Size() { + l.mu.RLock() + defer l.mu.RUnlock() + + if i < l.size { for n, current := 0, l.front; current != nil; current, n = current.Next, n+1 { if n == i { return current.Value diff --git a/collections/queue.go b/collections/queue.go index 736d3c2..ea2602c 100644 --- a/collections/queue.go +++ b/collections/queue.go @@ -56,15 +56,28 @@ func (q *ArrayQueue[T]) Poll() T { } func (q *ArrayQueue[T]) Peek() T { + q.lock.Lock() + defer q.lock.Unlock() + + if q.size == 0 { + panic("empty") + } + return q.array[0] } // 栈大小 func (q *ArrayQueue[T]) Size() int { + q.lock.Lock() + defer q.lock.Unlock() + return q.size } // 栈是否为空 func (q *ArrayQueue[T]) IsEmpty() bool { + q.lock.Lock() + defer q.lock.Unlock() + return q.size == 0 } diff --git a/collections/stack/stack.go b/collections/stack/stack.go index a5f2393..544b910 100644 --- a/collections/stack/stack.go +++ b/collections/stack/stack.go @@ -60,22 +60,29 @@ func (s *ArrayStack[T]) Pop() T { // 获取栈顶元素 func (s *ArrayStack[T]) Peek() T { - // 栈中元素已空 + s.lock.Lock() + defer s.lock.Unlock() + if s.size == 0 { panic("empty") } - // 栈顶元素值 v := s.array[s.size-1] return v } // 栈大小 func (s *ArrayStack[T]) Size() int { + s.lock.Lock() + defer s.lock.Unlock() + return s.size } // 栈是否为空 func (s *ArrayStack[T]) IsEmpty() bool { + s.lock.Lock() + defer s.lock.Unlock() + return s.size == 0 } diff --git a/concurrent/delay_queue/mem_store.go b/concurrent/delay_queue/mem_store.go index 99f3d45..739260b 100644 --- a/concurrent/delay_queue/mem_store.go +++ b/concurrent/delay_queue/mem_store.go @@ -59,10 +59,13 @@ func (s *memStore[T]) Push(ctx context.Context, v T) error { func (s *memStore[T]) Pop() (T, error) { for { - _, exist := s.Peek() - if exist { - return s.h.Pop().(T), nil + s.mu.Lock() + if s.h.Len() > 0 { + v := s.h.Pop().(T) + s.mu.Unlock() + return v, nil } + s.mu.Unlock() time.Sleep(time.Millisecond * 10) } @@ -80,9 +83,15 @@ func (s *memStore[T]) Peek() (T, bool) { } func (s *memStore[T]) Len() int { + s.mu.Lock() + defer s.mu.Unlock() + return s.h.Len() } func (s *memStore[T]) IsEmpty() bool { - return s.Len() == 0 + s.mu.Lock() + defer s.mu.Unlock() + + return s.h.Len() == 0 } diff --git a/go.mod b/go.mod index eb2421f..a17aff1 100644 --- a/go.mod +++ b/go.mod @@ -37,6 +37,7 @@ require ( github.com/dgryski/go-rendezvous v0.0.0-20200823014737-9f7001d12a5f // indirect github.com/fastly/go-utils v0.0.0-20180712184237-d95a45783239 // indirect github.com/go-playground/locales v0.14.1 // indirect + github.com/hashicorp/go-version v1.9.0 // indirect github.com/jehiah/go-strftime v0.0.0-20171201141054-1d33003b3869 // indirect github.com/jonboulle/clockwork v0.4.0 // indirect github.com/lestrrat/go-envload v0.0.0-20180220120943-6ed08b54a570 // indirect diff --git a/go.sum b/go.sum index 6753266..7e79b69 100644 --- a/go.sum +++ b/go.sum @@ -63,6 +63,8 @@ github.com/google/go-cmp v0.3.0/go.mod h1:8QqcDgzrUqlUb/G2PQTWiueGozuR1884gddMyw github.com/google/go-cmp v0.3.1/go.mod h1:8QqcDgzrUqlUb/G2PQTWiueGozuR1884gddMywk6iLU= github.com/google/go-cmp v0.4.0/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/gNBxE= github.com/google/gofuzz v1.0.0/go.mod h1:dBl0BpW6vV/+mYPU4Po3pmUjxk6FQPldtuIdl/M65Eg= +github.com/hashicorp/go-version v1.9.0 h1:CeOIz6k+LoN3qX9Z0tyQrPtiB1DFYRPfCIBtaXPSCnA= +github.com/hashicorp/go-version v1.9.0/go.mod h1:fltr4n8CU8Ke44wwGCBoEymUuxUHl09ZGVZPK5anwXA= github.com/jehiah/go-strftime v0.0.0-20171201141054-1d33003b3869 h1:IPJ3dvxmJ4uczJe5YQdrYB16oTJlGSC/OyZDqUk9xX4= github.com/jehiah/go-strftime v0.0.0-20171201141054-1d33003b3869/go.mod h1:cJ6Cj7dQo+O6GJNiMx+Pa94qKj+TG8ONdKHgMNIyyag= github.com/jonboulle/clockwork v0.4.0 h1:p4Cf1aMWXnXAUh8lVfewRBx1zaTSYKrKMF2g3ST4RZ4= diff --git a/ketama/ketama.go b/ketama/ketama.go index 208dbf3..b00c1ac 100644 --- a/ketama/ketama.go +++ b/ketama/ketama.go @@ -18,6 +18,9 @@ func New() *Ketama { } func (k *Ketama) Synchronize() { + if k.mu == nil { + k.mu = &locker.RWLock{} + } k.mu.Synchronize() } diff --git a/locker/empty_locker.go b/locker/empty_locker.go index 50360f8..2400342 100644 --- a/locker/empty_locker.go +++ b/locker/empty_locker.go @@ -3,6 +3,8 @@ package locker var _ rwLocker = &emptyLocker{} var _ locker = &emptyLocker{} +var EmptyLocker RWLocker = &emptyLocker{} + type emptyLocker struct { } diff --git a/locker/locker.go b/locker/locker.go index 692060b..69f86a1 100644 --- a/locker/locker.go +++ b/locker/locker.go @@ -17,6 +17,8 @@ type rwLocker interface { TryRLock() bool } +type RWLocker = rwLocker + func NewLocker() *sync.Mutex { return &sync.Mutex{} } diff --git a/locker/source_locker.go b/locker/source_locker.go index 1f6625b..23001c8 100644 --- a/locker/source_locker.go +++ b/locker/source_locker.go @@ -2,20 +2,16 @@ package locker import ( "context" - "fmt" - "sync/atomic" redis_store "github.com/charlienet/go-mixed/locker/redis" "github.com/charlienet/go-mixed/redis" ) -// 带计数器锁 type countLocker struct { rw rwLocker Count int32 } -// SourceLocker 资源锁 type SourceLocker struct { m RWLocker distributedLocker DistributedLocker @@ -28,7 +24,7 @@ func NewSourceLocker() *SourceLocker { locks: make(map[string]*countLocker), } - l.m.Synchronize() + l.m = NewRWLocker() return l } @@ -43,39 +39,25 @@ func (s *SourceLocker) WithDistributedLocker(distributed DistributedLocker) *Sou } func (s *SourceLocker) Lock(key string) { - s.m.RLock() + s.m.Lock() l, ok := s.locks[key] - s.m.RUnlock() - if ok { - atomic.AddInt32(&l.Count, 1) - l.rw.Lock() - - fmt.Println("加锁") + l.Count++ } else { - // 加锁,再次检查是否已经具有锁 - s.m.Lock() - if l2, ok := s.locks[key]; ok { - s.m.Unlock() - - l2.rw.Lock() - fmt.Println("二次检查加锁") - } else { - n := NewRWLocker() - s.locks[key] = &countLocker{rw: n, Count: 1} - - s.m.Unlock() - - n.Lock() - } + n := NewRWLocker() + l = &countLocker{rw: n, Count: 1} + s.locks[key] = l } + s.m.Unlock() + + l.rw.Lock() } func (s *SourceLocker) Unlock(key string) { s.m.Lock() if l, ok := s.locks[key]; ok { - atomic.AddInt32(&l.Count, -1) + l.Count-- l.rw.Unlock() if s.distributedLocker != nil { @@ -90,19 +72,25 @@ func (s *SourceLocker) Unlock(key string) { } func (s *SourceLocker) TryLock(key string) bool { - // 加读锁 - s.m.RLock() + s.m.Lock() l, ok := s.locks[key] - s.m.RUnlock() if ok { - ret := l.rw.TryLock() - return ret + l.Count++ } else { - s.m.Lock() n := NewRWLocker() - s.locks[key] = &countLocker{rw: n, Count: 1} - s.m.Unlock() - - return n.TryLock() + l = &countLocker{rw: n, Count: 1} + s.locks[key] = l } + s.m.Unlock() + + if !l.rw.TryLock() { + s.m.Lock() + l.Count-- + if l.Count == 0 { + delete(s.locks, key) + } + s.m.Unlock() + return false + } + return true } diff --git a/locker/synchronizeable.go b/locker/synchronizeable.go index 20961f7..6395611 100644 --- a/locker/synchronizeable.go +++ b/locker/synchronizeable.go @@ -24,9 +24,9 @@ func (w *Locker) WithDistributedLocker(d DistributedLocker) *Locker { } func (w *Locker) Synchronize() *Locker { - if w.mu == nil || w.mu == empty { + w.once.Do(func() { w.mu = NewLocker() - } + }) return w } @@ -59,49 +59,54 @@ type SpinLocker struct { } func (w *SpinLocker) Synchronize() { - if w.mu == nil || w.mu == empty { + w.once.Do(func() { w.mu = NewSpinLocker() - } + }) } -type RWLocker struct { +type WithRWLocker interface { + rwLocker + Synchronize() WithRWLocker +} + +type RWLock struct { once sync.Once mu rwLocker } -func (w *RWLocker) Synchronize() *RWLocker { - if w.mu == nil || w.mu == empty { +func (w *RWLock) Synchronize() WithRWLocker { + w.once.Do(func() { w.mu = NewRWLocker() - } + }) return w } -func (w *RWLocker) Lock() { +func (w *RWLock) Lock() { w.ensureLocker().mu.Lock() } -func (w *RWLocker) TryLock() bool { +func (w *RWLock) TryLock() bool { return w.ensureLocker().mu.TryLock() } -func (w *RWLocker) Unlock() { +func (w *RWLock) Unlock() { w.ensureLocker().mu.Unlock() } -func (w *RWLocker) RLock() { +func (w *RWLock) RLock() { w.ensureLocker().mu.RLock() } -func (w *RWLocker) TryRLock() bool { +func (w *RWLock) TryRLock() bool { return w.ensureLocker().mu.TryRLock() } -func (w *RWLocker) RUnlock() { +func (w *RWLock) RUnlock() { w.ensureLocker().mu.RUnlock() } -func (w *RWLocker) ensureLocker() *RWLocker { +func (w *RWLock) ensureLocker() *RWLock { w.once.Do(func() { if w.mu == nil { log.Println("初始化一个空锁") diff --git a/locker/synchronizeable_test.go b/locker/synchronizeable_test.go index dec8350..b5d93dc 100644 --- a/locker/synchronizeable_test.go +++ b/locker/synchronizeable_test.go @@ -17,7 +17,7 @@ func TestLocker(t *testing.T) { } func TestNew(t *testing.T) { - var a locker.RWLocker + var a locker.RWLock a.Synchronize() } @@ -30,8 +30,8 @@ func TestSpinLocker(t *testing.T) { defer l.Unlock() } -func TestRWLocker(t *testing.T) { - var l locker.RWLocker +func TestRWLock(t *testing.T) { + var l locker.RWLock l.Lock() } diff --git a/maps/hash_map.go b/maps/hash_map.go index 025f75a..4fd8500 100644 --- a/maps/hash_map.go +++ b/maps/hash_map.go @@ -125,6 +125,9 @@ func (m *hashMap[K, V]) Clear() { } func (m *hashMap[K, V]) Count() int { + m.opt.mu.RLock() + defer m.opt.mu.RUnlock() + return len(m.m) } diff --git a/maps/rwlock_map.go b/maps/rwlock_map.go index a13635c..428d441 100644 --- a/maps/rwlock_map.go +++ b/maps/rwlock_map.go @@ -65,10 +65,16 @@ func (m *rw_map[K, V]) Shrink() map[K]V { } func (m *rw_map[K, V]) Exist(key K) bool { + m.mu.RLock() + defer m.mu.RUnlock() + return m.m.Exist(key) } func (m *rw_map[K, V]) Count() int { + m.mu.RLock() + defer m.mu.RUnlock() + return m.m.Count() } diff --git a/sets/hash_set.go b/sets/hash_set.go index dabdf78..b55a5fd 100644 --- a/sets/hash_set.go +++ b/sets/hash_set.go @@ -19,7 +19,8 @@ type hash_set[T constraints.Ordered] struct { func NewHashSet[T constraints.Ordered](values ...T) *hash_set[T] { set := hash_set[T]{ - m: make(map[T]struct{}, len(values)), + m: make(map[T]struct{}, len(values)), + locker: locker.EmptyLocker, } set.Add(values...) @@ -27,7 +28,7 @@ func NewHashSet[T constraints.Ordered](values ...T) *hash_set[T] { } func (s *hash_set[T]) Sync() *hash_set[T] { - s.locker.Synchronize() + s.locker = locker.NewRWLocker() return s }