improve gmlock

This commit is contained in:
john
2019-06-18 17:31:48 +08:00
parent 048c3d5025
commit 17898cc747
8 changed files with 134 additions and 127 deletions

View File

@ -6,7 +6,6 @@
package garray
type apiSliceInterface interface {
Slice() []interface{}
}

View File

@ -4,11 +4,12 @@
// If a copy of the MIT was not distributed with this file,
// You can obtain one at https://github.com/gogf/gf.
// Package mutex provides switch for sync.Mutex for concurrent safe feature.
// Package mutex provides switch of concurrent safe feature for sync.Mutex.
package mutex
import "sync"
// Mutex is a sync.Mutex with a switch of concurrent safe feature.
type Mutex struct {
sync.Mutex
safe bool

View File

@ -4,11 +4,12 @@
// If a copy of the MIT was not distributed with this file,
// You can obtain one at https://github.com/gogf/gf.
// Package rwmutex provides switch for sync.RWMutex for concurrent safe feature.
// Package rwmutex provides switch of concurrent safe feature for sync.RWMutex.
package rwmutex
import "sync"
// RWMutex is a sync.RWMutex with a switch of concurrent safe feature.
type RWMutex struct {
sync.RWMutex
safe bool

View File

@ -14,46 +14,46 @@ var (
locker = New()
)
// TryLock tries locking the <key> with write lock,
// it returns true if success, or if there's a write/read lock the <key>,
// TryLock tries locking the <key> with writing lock,
// it returns true if success, or if there's a write/reading lock the <key>,
// it returns false. The parameter <expire> specifies the max duration it locks.
func TryLock(key string, expire...time.Duration) bool {
return locker.TryLock(key, expire...)
}
// Lock locks the <key> with write lock.
// If there's a write/read lock the <key>,
// Lock locks the <key> with writing lock.
// If there's a write/reading lock the <key>,
// it will blocks until the lock is released.
// The parameter <expire> specifies the max duration it locks.
func Lock(key string, expire...time.Duration) {
locker.Lock(key, expire...)
}
// Unlock unlocks the write lock of the <key>.
// Unlock unlocks the writing lock of the <key>.
func Unlock(key string) {
locker.Unlock(key)
}
// TryRLock tries locking the <key> with read lock.
// It returns true if success, or if there's a write lock on <key>, it returns false.
// TryRLock tries locking the <key> with reading lock.
// It returns true if success, or if there's a writing lock on <key>, it returns false.
func TryRLock(key string) bool {
return locker.TryRLock(key)
}
// RLock locks the <key> with read lock.
// If there's a write lock on <key>,
// it will blocks until the write lock is released.
// RLock locks the <key> with reading lock.
// If there's a writing lock on <key>,
// it will blocks until the writing lock is released.
func RLock(key string) {
locker.RLock(key)
}
// RUnlock unlocks the read lock of the <key>.
// RUnlock unlocks the reading lock of the <key>.
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.
// TryLockFunc locks the <key> with writing lock and callback function <f>.
// It returns true if success, or else if there's a write/reading lock the <key>, it return false.
//
// It releases the lock after <f> is executed.
//
@ -62,8 +62,8 @@ 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.
// TryRLockFunc locks the <key> with reading lock and callback function <f>.
// It returns true if success, or else if there's a writing lock the <key>, it returns false.
//
// It releases the lock after <f> is executed.
//
@ -72,8 +72,8 @@ 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>,
// LockFunc locks the <key> with writing lock and callback function <f>.
// If there's a write/reading lock the <key>,
// it will blocks until the lock is released.
//
// It releases the lock after <f> is executed.
@ -83,8 +83,8 @@ func LockFunc(key string, f func(), expire...time.Duration) {
locker.LockFunc(key, f, expire...)
}
// RLockFunc locks the <key> with read lock and callback function <f>.
// If there's a write lock the <key>,
// RLockFunc locks the <key> with reading lock and callback function <f>.
// If there's a writing lock the <key>,
// it will blocks until the lock is released.
//
// It releases the lock after <f> is executed.

View File

@ -25,50 +25,50 @@ func New() *Locker {
}
}
// TryLock tries locking the <key> with write lock,
// it returns true if success, or if there's a write/read lock the <key>,
// it returns false. The parameter <expire> specifies the max duration it locks.
// TryLock tries locking the <key> with writing lock,
// it returns true if success, or it returns false if there's a writing/reading lock the <key>.
// The parameter <expire> specifies the max duration it locks.
func (l *Locker) TryLock(key string, expire...time.Duration) bool {
return l.doLock(key, l.getExpire(expire...), true)
}
// Lock locks the <key> with write lock.
// If there's a write/read lock the <key>,
// Lock locks the <key> with writing lock.
// If there's a write/reading lock the <key>,
// it will blocks until the lock is released.
// The parameter <expire> specifies the max duration it locks.
func (l *Locker) Lock(key string, expire...time.Duration) {
l.doLock(key, l.getExpire(expire...), false)
}
// Unlock unlocks the write lock of the <key>.
// Unlock unlocks the writing lock of the <key>.
func (l *Locker) Unlock(key string) {
if v := l.m.Get(key); v != nil {
v.(*Mutex).Unlock()
}
}
// TryRLock tries locking the <key> with read lock.
// It returns true if success, or if there's a write lock on <key>, it returns false.
// TryRLock tries locking the <key> with reading lock.
// It returns true if success, or if there's a writing lock on <key>, it returns false.
func (l *Locker) TryRLock(key string) bool {
return l.doRLock(key, true)
}
// RLock locks the <key> with read lock.
// If there's a write lock on <key>,
// it will blocks until the write lock is released.
// RLock locks the <key> with reading lock.
// If there's a writing lock on <key>,
// it will blocks until the writing lock is released.
func (l *Locker) RLock(key string) {
l.doRLock(key, false)
}
// RUnlock unlocks the read lock of the <key>.
// RUnlock unlocks the reading lock of the <key>.
func (l *Locker) RUnlock(key string) {
if v := l.m.Get(key); v != nil {
v.(*Mutex).RUnlock()
}
}
// 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.
// TryLockFunc locks the <key> with writing lock and callback function <f>.
// It returns true if success, or else if there's a write/reading lock the <key>, it return false.
//
// It releases the lock after <f> is executed.
//
@ -82,8 +82,8 @@ func (l *Locker) TryLockFunc(key string, f func(), expire...time.Duration) bool
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.
// TryRLockFunc locks the <key> with reading lock and callback function <f>.
// It returns true if success, or else if there's a writing lock the <key>, it returns false.
//
// It releases the lock after <f> is executed.
//
@ -97,8 +97,8 @@ func (l *Locker) TryRLockFunc(key string, f func()) bool {
return false
}
// LockFunc locks the <key> with write lock and callback function <f>.
// If there's a write/read lock the <key>,
// LockFunc locks the <key> with writing lock and callback function <f>.
// If there's a write/reading lock the <key>,
// it will blocks until the lock is released.
//
// It releases the lock after <f> is executed.
@ -110,8 +110,8 @@ func (l *Locker) LockFunc(key string, f func(), expire...time.Duration) {
f()
}
// RLockFunc locks the <key> with read lock and callback function <f>.
// If there's a write lock the <key>,
// RLockFunc locks the <key> with reading lock and callback function <f>.
// If there's a writing lock the <key>,
// it will blocks until the lock is released.
//
// It releases the lock after <f> is executed.
@ -137,8 +137,8 @@ func (l *Locker) getExpire(expire...time.Duration) time.Duration {
// It returns true if success, or else returns false.
//
// The parameter <try> is true,
// it returns false immediately if it fails getting the write lock.
// If <true> is false, it blocks until it gets the write lock.
// it returns false immediately if it fails getting the writing lock.
// If <true> is false, it blocks until it gets the writing lock.
//
// The parameter <expire> specifies the max duration it locks.
func (l *Locker) doLock(key string, expire time.Duration, try bool) bool {
@ -164,8 +164,8 @@ func (l *Locker) doLock(key string, expire time.Duration, try bool) bool {
// It returns true if success, or else returns false.
//
// The parameter <try> is true,
// it returns false immediately if it fails getting the read lock.
// If <true> is false, it blocks until it gets the read lock.
// it returns false immediately if it fails getting the reading lock.
// If <true> is false, it blocks until it gets the reading lock.
func (l *Locker) doRLock(key string, try bool) bool {
mu := l.getOrNewMutex(key)
ok := true

View File

@ -8,98 +8,114 @@ package gmlock
import (
"github.com/gogf/gf/g/container/gtype"
"runtime"
"sync"
)
// The high level Mutex.
// The high level RWMutex.
// It wraps the sync.RWMutex to implements more rich features.
type Mutex struct {
mu sync.RWMutex
wid *gtype.Int64 // Unique id, used for multiple safely Unlock.
number *gtype.Int // Locking number.
// 0: writing lock false;
// 1: writing lock true;
// >=2: reading lock;
mu sync.RWMutex
wid *gtype.Int64 // Unique id, used for multiple and safe logic Unlock.
locking *gtype.Bool // Locking mark for atomic operation for *Lock and Try*Lock functions.
// There must be only one locking operation at the same time for concurrent safe purpose.
state *gtype.Int32 // Locking state:
// 0: writing lock false;
// -1: writing lock true;
// >=1: reading lock;
}
// NewMutex creates and returns a new mutex.
func NewMutex() *Mutex {
return &Mutex{
wid : gtype.NewInt64(),
number : gtype.NewInt(),
wid : gtype.NewInt64(),
state : gtype.NewInt32(),
locking : gtype.NewBool(),
}
}
// Lock locks mutex for writing.
// Lock locks the mutex for writing.
// If the lock is already locked for reading or writing,
// Lock blocks until the lock is available.
func (m *Mutex) Lock() {
m.mu.Lock()
m.number.Set(1)
m.wid.Add(1)
if m.locking.Cas(false, true) {
m.mu.Lock()
// State should be changed after locks.
m.state.Set(-1)
m.wid.Add(1)
m.locking.Set(false)
} else {
runtime.Gosched()
m.Lock()
}
}
// Unlock unlocks the write lock.
// It is safe to be called multiple times.
// Unlock unlocks the writing lock.
// It is safe to be called multiple times if there's any locks or not.
func (m *Mutex) Unlock() {
if m.number.Cas(1, 0) {
if m.state.Cas(-1, 0) {
m.mu.Unlock()
}
}
// TryLock tries locking the mutex for writing.
// It returns true if success, or if there's a write/reading lock on the mutex,
// it returns false.
func (m *Mutex) TryLock() bool {
if m.locking.Cas(false, true) {
m.mu.Lock()
// State should be changed after locks.
m.state.Set(-1)
m.wid.Add(1)
m.locking.Set(false)
return true
}
return false
}
// RLock locks mutex for reading.
// If the mutex is already locked for writing,
// It blocks until the lock is available.
func (m *Mutex) RLock() {
m.mu.RLock()
m.number.Add(2)
if m.locking.Cas(false, true) {
m.mu.RLock()
// State should be changed after locks.
m.state.Add(1)
m.locking.Set(false)
} else {
runtime.Gosched()
m.RLock()
}
}
// RUnlock undoes a single RLock call;
// it does not affect other simultaneous readers.
// 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.
// RUnlock unlocks the reading lock.
// It is safe to be called multiple times if there's any locks or not.
func (m *Mutex) RUnlock() {
if n := m.number.Val(); n >= 2 && n%2 == 0 {
if n := m.number.Add(-2); n >= 0 && n%2 == 0 {
m.mu.RUnlock()
} else {
m.number.Add(2)
}
if n := m.state.Val(); n >= 1 {
if m.state.Cas(n, n - 1) {
m.mu.RUnlock()
} else {
m.RUnlock()
}
}
}
// 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 (m *Mutex) TryLock() bool {
if m.number.Cas(0, 1) {
m.mu.Lock()
m.wid.Add(1)
return true
}
return false
}
// TryRLock tries locking the mutex for reading.
// It returns true if success, or if there's a writing lock on the mutex, it returns false.
//
// Note that it's not an atomic operation.
//
// TODO It should be an atomic operation.
func (m *Mutex) TryRLock() bool {
// There must be no writing lock on the mutex.
if n := m.number.Val(); n%2 == 0 {
m.mu.RLock()
m.number.Add(2)
return true
if m.locking.Cas(false, true) {
if m.state.Val() >= 0 {
m.mu.RLock()
m.state.Add(1)
m.locking.Set(false)
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 true if success, or if there's a write/reading lock on the mutex,
// it returns false.
//
// It releases the lock after <f> is executed.
@ -113,7 +129,7 @@ func (m *Mutex) TryLockFunc(f func()) bool {
}
// 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 returns true if success, or if there's a writing lock on the mutex, it returns false.
//
// It releases the lock after <f> is executed.
func (m *Mutex) TryRLockFunc(f func()) bool {
@ -126,7 +142,7 @@ func (m *Mutex) TryRLockFunc(f func()) bool {
}
// 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.
// If there's a write/reading 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()) {
@ -136,7 +152,7 @@ func (m *Mutex) LockFunc(f func()) {
}
// 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.
// If there's a writing 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()) {

View File

@ -2,6 +2,7 @@ package main
import (
"github.com/gogf/gf/g/container/garray"
"github.com/gogf/gf/g/os/glog"
"github.com/gogf/gf/g/os/gmlock"
"github.com/gogf/gf/g/test/gtest"
"time"
@ -13,22 +14,19 @@ func main() {
go func() {
mu.LockFunc(func() {
array.Append(1)
time.Sleep(100 * time.Millisecond)
time.Sleep(10000 * time.Millisecond)
})
}()
go func() {
time.Sleep(50 * time.Millisecond)
mu.LockFunc(func() {
array.Append(1)
})
}()
go func() {
time.Sleep(50 * time.Millisecond)
mu.LockFunc(func() {
array.Append(1)
})
}()
time.Sleep(10*time.Millisecond)
for i := 0; i < 10000; i++ {
go func(i int) {
time.Sleep(50 * time.Millisecond)
mu.LockFunc(func() {
glog.Print(i)
array.Append(1)
})
}(i)
}
go func() {
time.Sleep(60 * time.Millisecond)
mu.Unlock()

View File

@ -1,20 +1,12 @@
package main
import (
"github.com/gogf/gf/g"
"github.com/gogf/gf/g/net/ghttp"
"fmt"
"sync"
)
func main() {
s := g.Server()
s.BindHookHandler("/*any", ghttp.HOOK_BEFORE_SERVE, func(r *ghttp.Request) {
r.Response.SetAllowCrossDomainRequest("*", "PUT,GET,POST,DELETE,OPTIONS")
r.Response.Header().Set("Access-Control-Allow-Credentials", "true")
r.Response.Header().Set("Access-Control-Allow-Headers", "X-Requested-With, Content-Type, token")
})
s.Group("/v1").COMMON("*", func(r *ghttp.Request) {
r.Response.WriteJson(g.Map{"name": "john"})
})
s.SetPort(6789)
s.Run()
m := sync.RWMutex{}
m.Lock()
fmt.Println(m)
}