mirror of
https://gitee.com/johng/gf
synced 2026-06-06 16:21:40 +08:00
add TryLockFunc/TryRLockFunc for gmlock.Mutex
This commit is contained in:
@ -4,12 +4,13 @@
|
||||
// If a copy of the MIT was not distributed with this file,
|
||||
// You can obtain one at https://github.com/gogf/gf.
|
||||
|
||||
// Package gmlock implements a thread-safe memory locker.
|
||||
// Package gmlock implements a concurrent-safe memory-based locker.
|
||||
package gmlock
|
||||
|
||||
import "time"
|
||||
|
||||
var (
|
||||
// Default locker.
|
||||
locker = New()
|
||||
)
|
||||
|
||||
@ -51,6 +52,26 @@ func RUnlock(key string) {
|
||||
locker.RUnlock(key)
|
||||
}
|
||||
|
||||
// TryLockFunc locks the <key> with write lock and callback function <f>.
|
||||
// It returns true if success, or else if there's a write/read lock the <key>, it return false.
|
||||
//
|
||||
// It releases the lock after <f> is executed.
|
||||
//
|
||||
// The parameter <expire> specifies the max duration it locks.
|
||||
func TryLockFunc(key string, f func(), expire...time.Duration) bool {
|
||||
return locker.TryLockFunc(key, f, expire...)
|
||||
}
|
||||
|
||||
// TryRLockFunc locks the <key> with read lock and callback function <f>.
|
||||
// It returns true if success, or else if there's a write lock the <key>, it returns false.
|
||||
//
|
||||
// It releases the lock after <f> is executed.
|
||||
//
|
||||
// The parameter <expire> specifies the max duration it locks.
|
||||
func TryRLockFunc(key string, f func()) bool {
|
||||
return locker.TryRLockFunc(key, f)
|
||||
}
|
||||
|
||||
// LockFunc locks the <key> with write lock and callback function <f>.
|
||||
// If there's a write/read lock the <key>,
|
||||
// it will blocks until the lock is released.
|
||||
|
||||
@ -67,6 +67,36 @@ func (l *Locker) RUnlock(key string) {
|
||||
}
|
||||
}
|
||||
|
||||
// TryLockFunc locks the <key> with write lock and callback function <f>.
|
||||
// It returns true if success, or else if there's a write/read lock the <key>, it return false.
|
||||
//
|
||||
// It releases the lock after <f> is executed.
|
||||
//
|
||||
// The parameter <expire> specifies the max duration it locks.
|
||||
func (l *Locker) TryLockFunc(key string, f func(), expire...time.Duration) bool {
|
||||
if l.TryLock(key, expire...) {
|
||||
defer l.Unlock(key)
|
||||
f()
|
||||
return true
|
||||
}
|
||||
return false
|
||||
}
|
||||
|
||||
// TryRLockFunc locks the <key> with read lock and callback function <f>.
|
||||
// It returns true if success, or else if there's a write lock the <key>, it returns false.
|
||||
//
|
||||
// It releases the lock after <f> is executed.
|
||||
//
|
||||
// The parameter <expire> specifies the max duration it locks.
|
||||
func (l *Locker) TryRLockFunc(key string, f func()) bool {
|
||||
if l.TryRLock(key) {
|
||||
defer l.RUnlock(key)
|
||||
f()
|
||||
return true
|
||||
}
|
||||
return false
|
||||
}
|
||||
|
||||
// LockFunc locks the <key> with write lock and callback function <f>.
|
||||
// If there's a write/read lock the <key>,
|
||||
// it will blocks until the lock is released.
|
||||
@ -120,7 +150,6 @@ func (l *Locker) doLock(key string, expire time.Duration, try bool) bool {
|
||||
mu.Lock()
|
||||
}
|
||||
if ok && expire > 0 {
|
||||
// 异步goroutine计时处理
|
||||
wid := mu.wid.Val()
|
||||
gtimer.AddOnce(expire, func() {
|
||||
if wid == mu.wid.Val() {
|
||||
|
||||
@ -7,16 +7,17 @@
|
||||
package gmlock
|
||||
|
||||
import (
|
||||
"github.com/gogf/gf/g/container/gtype"
|
||||
"sync"
|
||||
"github.com/gogf/gf/g/container/gtype"
|
||||
"sync"
|
||||
)
|
||||
|
||||
// The mutex.
|
||||
// The high level Mutex.
|
||||
// It wraps the sync.RWMutex to implements more rich features.
|
||||
type Mutex struct {
|
||||
mu sync.RWMutex
|
||||
wid *gtype.Int64 // Unique id for this mutex.
|
||||
rcount *gtype.Int // RLock count.
|
||||
wcount *gtype.Int // Lock count.
|
||||
wid *gtype.Int64 // Unique id, used for multiple safely Unlock.
|
||||
rcount *gtype.Int // Reading locks count.
|
||||
wcount *gtype.Int // Writing locks count.
|
||||
}
|
||||
|
||||
// NewMutex creates and returns a new mutex.
|
||||
@ -31,72 +32,120 @@ func NewMutex() *Mutex {
|
||||
// Lock locks mutex for writing.
|
||||
// If the lock is already locked for reading or writing,
|
||||
// Lock blocks until the lock is available.
|
||||
func (l *Mutex) Lock() {
|
||||
l.wcount.Add(1)
|
||||
l.mu.Lock()
|
||||
l.wid.Add(1)
|
||||
func (m *Mutex) Lock() {
|
||||
m.wcount.Add(1)
|
||||
m.mu.Lock()
|
||||
m.wid.Add(1)
|
||||
}
|
||||
|
||||
// Unlock unlocks the write lock.
|
||||
// It is safe to be called multiple times.
|
||||
func (l *Mutex) Unlock() {
|
||||
if l.wcount.Val() > 0 {
|
||||
if l.wcount.Add(-1) >= 0 {
|
||||
l.mu.Unlock()
|
||||
func (m *Mutex) Unlock() {
|
||||
if m.wcount.Val() > 0 {
|
||||
if m.wcount.Add(-1) >= 0 {
|
||||
m.mu.Unlock()
|
||||
} else {
|
||||
l.wcount.Add(1)
|
||||
m.wcount.Add(1)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// RLock locks mutex for reading.
|
||||
func (l *Mutex) RLock() {
|
||||
l.rcount.Add(1)
|
||||
l.mu.RLock()
|
||||
// If the mutex is already locked for writing,
|
||||
// It blocks until the lock is available.
|
||||
func (m *Mutex) RLock() {
|
||||
m.rcount.Add(1)
|
||||
m.mu.RLock()
|
||||
}
|
||||
|
||||
// RUnlock undoes a single RLock call;
|
||||
// it does not affect other simultaneous readers.
|
||||
// It is a run-time error if rw is not locked for reading
|
||||
// It is a run-time error if mutex is not locked for reading
|
||||
// on entry to RUnlock.
|
||||
// It is safe to be called multiple times.
|
||||
func (l *Mutex) RUnlock() {
|
||||
if l.rcount.Val() > 0 {
|
||||
if l.rcount.Add(-1) >= 0 {
|
||||
l.mu.RUnlock()
|
||||
func (m *Mutex) RUnlock() {
|
||||
if m.rcount.Val() > 0 {
|
||||
if m.rcount.Add(-1) >= 0 {
|
||||
m.mu.RUnlock()
|
||||
} else {
|
||||
l.rcount.Add(1)
|
||||
m.rcount.Add(1)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// TryLock tries locking the mutex with write lock,
|
||||
// it returns true if success, or if there's a write/read lock the mutex,
|
||||
// TryLock tries locking the mutex for writing.
|
||||
// It returns true if success, or if there's a write/read lock on the mutex,
|
||||
// it returns false.
|
||||
func (l *Mutex) TryLock() bool {
|
||||
func (m *Mutex) TryLock() bool {
|
||||
// The first check, but it cannot ensure the atomicity.
|
||||
if l.wcount.Val() == 0 && l.rcount.Val() == 0 {
|
||||
// The second check, it can ensure the atomicity.
|
||||
if l.wcount.Add(1) == 1 {
|
||||
l.mu.Lock()
|
||||
l.wid.Add(1)
|
||||
if m.wcount.Val() == 0 && m.rcount.Val() == 0 {
|
||||
// The second check, it ensures the atomicity with atomic Add.
|
||||
if m.wcount.Add(1) == 1 {
|
||||
m.mu.Lock()
|
||||
m.wid.Add(1)
|
||||
return true
|
||||
} else {
|
||||
l.wcount.Add(-1)
|
||||
m.wcount.Add(-1)
|
||||
}
|
||||
}
|
||||
return false
|
||||
}
|
||||
|
||||
// TryRLock tries locking the mutex with read lock.
|
||||
// It returns true if success, or if there's a write lock on mutex, it returns false.
|
||||
func (l *Mutex) TryRLock() bool {
|
||||
// TryRLock tries locking the mutex for reading.
|
||||
// It returns true if success, or if there's a write lock on the mutex, it returns false.
|
||||
func (m *Mutex) TryRLock() bool {
|
||||
// There must be no write lock on mutex.
|
||||
if l.wcount.Val() == 0 {
|
||||
l.rcount.Add(1)
|
||||
l.mu.RLock()
|
||||
if m.wcount.Val() == 0 {
|
||||
m.rcount.Add(1)
|
||||
m.mu.RLock()
|
||||
return true
|
||||
}
|
||||
return false
|
||||
}
|
||||
|
||||
// TryLockFunc tries locking the mutex for writing with given callback function <f>.
|
||||
// it returns true if success, or if there's a write/read lock on the mutex,
|
||||
// it returns false.
|
||||
//
|
||||
// It releases the lock after <f> is executed.
|
||||
func (m *Mutex) TryLockFunc(f func()) bool {
|
||||
if m.TryLock() {
|
||||
defer m.Unlock()
|
||||
f()
|
||||
return true
|
||||
}
|
||||
return false
|
||||
}
|
||||
|
||||
// TryRLockFunc tries locking the mutex for reading with given callback function <f>.
|
||||
// It returns true if success, or if there's a write lock on the mutex, it returns false.
|
||||
//
|
||||
// It releases the lock after <f> is executed.
|
||||
func (m *Mutex) TryRLockFunc(f func()) bool {
|
||||
if m.TryRLock() {
|
||||
defer m.RUnlock()
|
||||
f()
|
||||
return true
|
||||
}
|
||||
return false
|
||||
}
|
||||
|
||||
// LockFunc locks the mutex for writing with given callback function <f>.
|
||||
// If there's a write/read lock the mutex, it will blocks until the lock is released.
|
||||
//
|
||||
// It releases the lock after <f> is executed.
|
||||
func (m *Mutex) LockFunc(f func()) {
|
||||
m.Lock()
|
||||
defer m.Unlock()
|
||||
f()
|
||||
}
|
||||
|
||||
// RLockFunc locks the mutex for reading with given callback function <f>.
|
||||
// If there's a write lock the mutex, it will blocks until the lock is released.
|
||||
//
|
||||
// It releases the lock after <f> is executed.
|
||||
func (m *Mutex) RLockFunc(f func()) {
|
||||
m.RLock()
|
||||
defer m.RUnlock()
|
||||
f()
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user