From 055074246e2856823ea6dcf0a9fe2d3183a71555 Mon Sep 17 00:00:00 2001 From: John Date: Wed, 5 Jun 2019 23:50:24 +0800 Subject: [PATCH] add TryLockFunc/TryRLockFunc for gmlock.Mutex --- g/os/gmlock/gmlock.go | 23 ++++++- g/os/gmlock/gmlock_locker.go | 31 ++++++++- g/os/gmlock/gmlock_mutex.go | 127 ++++++++++++++++++++++++----------- 3 files changed, 140 insertions(+), 41 deletions(-) diff --git a/g/os/gmlock/gmlock.go b/g/os/gmlock/gmlock.go index a31aee8b8..18bc88fa0 100644 --- a/g/os/gmlock/gmlock.go +++ b/g/os/gmlock/gmlock.go @@ -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 with write lock and callback function . +// It returns true if success, or else if there's a write/read lock the , it return false. +// +// It releases the lock after is executed. +// +// The parameter 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 with read lock and callback function . +// It returns true if success, or else if there's a write lock the , it returns false. +// +// It releases the lock after is executed. +// +// The parameter specifies the max duration it locks. +func TryRLockFunc(key string, f func()) bool { + return locker.TryRLockFunc(key, f) +} + // LockFunc locks the with write lock and callback function . // If there's a write/read lock the , // it will blocks until the lock is released. diff --git a/g/os/gmlock/gmlock_locker.go b/g/os/gmlock/gmlock_locker.go index bd653eb13..6eeafbff7 100644 --- a/g/os/gmlock/gmlock_locker.go +++ b/g/os/gmlock/gmlock_locker.go @@ -67,6 +67,36 @@ func (l *Locker) RUnlock(key string) { } } +// TryLockFunc locks the with write lock and callback function . +// It returns true if success, or else if there's a write/read lock the , it return false. +// +// It releases the lock after is executed. +// +// The parameter 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 with read lock and callback function . +// It returns true if success, or else if there's a write lock the , it returns false. +// +// It releases the lock after is executed. +// +// The parameter 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 with write lock and callback function . // If there's a write/read lock the , // 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() { diff --git a/g/os/gmlock/gmlock_mutex.go b/g/os/gmlock/gmlock_mutex.go index fc4d992a2..4faf7b82d 100644 --- a/g/os/gmlock/gmlock_mutex.go +++ b/g/os/gmlock/gmlock_mutex.go @@ -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 . +// it returns true if success, or if there's a write/read lock on the mutex, +// it returns false. +// +// It releases the lock after 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 . +// It returns true if success, or if there's a write lock on the mutex, it returns false. +// +// It releases the lock after 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 . +// If there's a write/read lock the mutex, it will blocks until the lock is released. +// +// It releases the lock after is executed. +func (m *Mutex) LockFunc(f func()) { + m.Lock() + defer m.Unlock() + f() +} + +// RLockFunc locks the mutex for reading with given callback function . +// If there's a write lock the mutex, it will blocks until the lock is released. +// +// It releases the lock after is executed. +func (m *Mutex) RLockFunc(f func()) { + m.RLock() + defer m.RUnlock() + f() +}