add TryLockFunc/TryRLockFunc for gmlock.Mutex

This commit is contained in:
John
2019-06-05 23:50:24 +08:00
parent 4bbe51fb4b
commit 055074246e
3 changed files with 140 additions and 41 deletions

View File

@ -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.

View File

@ -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() {

View File

@ -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()
}