From bd97d7d94e06b72ca8d6ed53f072e81348bd64d6 Mon Sep 17 00:00:00 2001 From: John Date: Sat, 13 Jul 2019 16:41:23 +0800 Subject: [PATCH] improve gmutex --- g/os/gmutex/gmutex.go | 27 ++++++++++++--------------- g/os/gmutex/gmutex_bench_test.go | 4 +++- geg/errors/gerror/gerror1.go | 4 ++-- geg/errors/gerror/gerror3.go | 4 ++-- geg/errors/gerror/gerror4.go | 23 +++++++++++++++++++++++ geg/errors/gerror/gerror5.go | 22 ++++++++++++++++++++++ geg/os/gmutex/gmutex_basic.go | 29 +++++++++++++++++++++++++++++ geg/os/gmutex/gmutex_func.go | 22 ++++++++++++++++++++++ 8 files changed, 115 insertions(+), 20 deletions(-) create mode 100644 geg/errors/gerror/gerror4.go create mode 100644 geg/errors/gerror/gerror5.go create mode 100644 geg/os/gmutex/gmutex_basic.go create mode 100644 geg/os/gmutex/gmutex_func.go diff --git a/g/os/gmutex/gmutex.go b/g/os/gmutex/gmutex.go index 7acc97df9..11fa764fa 100644 --- a/g/os/gmutex/gmutex.go +++ b/g/os/gmutex/gmutex.go @@ -39,9 +39,8 @@ func New() *Mutex { // Lock blocks until the lock is available. func (m *Mutex) Lock() { for { - // If there're no readers pending and writing lock currently, - // then do the writing lock checks. - if m.reader.Val() == 0 && m.state.Cas(0, -1) { + // If there're no writing lock currently, then do the writing lock checks. + if m.state.Cas(0, -1) { return } m.writer.Add(1) @@ -55,13 +54,11 @@ func (m *Mutex) Lock() { func (m *Mutex) Unlock() { if m.state.Cas(-1, 0) { // Writing lock unlocks, then first check the blocked readers. - if n := m.reader.Val(); n > 0 { - // If there're readers blocked, unlock them with preemption. - for ; n > 0; n-- { - m.reading <- struct{}{} - } - return + // If there're readers blocked, unlock them with preemption. + for n := m.reader.Val(); n > 0; n-- { + m.reading <- struct{}{} } + // Then it also gives the pending writers one chance. if m.writer.Val() > 0 { m.writing <- struct{}{} } @@ -72,7 +69,7 @@ func (m *Mutex) Unlock() { // 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.reader.Val() == 0 && m.state.Cas(0, -1) { + if m.state.Cas(0, -1) { return true } return false @@ -84,9 +81,8 @@ func (m *Mutex) TryLock() bool { func (m *Mutex) RLock() { var n int32 for { - // If there're no writing lock and pending writers currently, - // then do the reading lock checks. - if n = m.state.Val(); n >= 0 && m.writer.Val() == 0 { + // If there're no writing lock currently, then do the reading lock checks. + if n = m.state.Val(); n >= 0 { if m.state.Cas(n, n+1) { return } else { @@ -94,6 +90,7 @@ func (m *Mutex) RLock() { continue } } + // Or else pending the reader. m.reader.Add(1) <-m.reading @@ -116,7 +113,7 @@ func (m *Mutex) RUnlock() { break } } - // Reading lock unlocks, then first check the blocked writers. + // Reading lock unlocks, then check the blocked writers. if n == 1 && m.writer.Val() > 0 { // No readers blocked, then the writers can take place. m.writing <- struct{}{} @@ -128,7 +125,7 @@ func (m *Mutex) RUnlock() { func (m *Mutex) TryRLock() bool { var n int32 for { - if n = m.state.Val(); n >= 0 && m.writer.Val() == 0 { + if n = m.state.Val(); n >= 0 { if m.state.Cas(n, n+1) { return true } else { diff --git a/g/os/gmutex/gmutex_bench_test.go b/g/os/gmutex/gmutex_bench_test.go index 9b7473bd2..470f38953 100644 --- a/g/os/gmutex/gmutex_bench_test.go +++ b/g/os/gmutex/gmutex_bench_test.go @@ -49,7 +49,9 @@ func Benchmark_GMutex_LockUnlock(b *testing.B) { func Benchmark_GMutex_TryLock(b *testing.B) { for i := 0; i < b.N; i++ { - gmu.TryLock() + if gmu.TryLock() { + defer gmu.Unlock() + } } } diff --git a/geg/errors/gerror/gerror1.go b/geg/errors/gerror/gerror1.go index 809fc81f6..5926723f3 100644 --- a/geg/errors/gerror/gerror1.go +++ b/geg/errors/gerror/gerror1.go @@ -8,11 +8,11 @@ import ( ) func Error1() error { - return errors.New("test") + return errors.New("test1") } func Error2() error { - return gerror.New("test") + return gerror.New("test2") } func main() { diff --git a/geg/errors/gerror/gerror3.go b/geg/errors/gerror/gerror3.go index d587ec016..27b5158a3 100644 --- a/geg/errors/gerror/gerror3.go +++ b/geg/errors/gerror/gerror3.go @@ -8,11 +8,11 @@ import ( ) func Error1() error { - return errors.New("test") + return errors.New("test1") } func Error2() error { - return gerror.New("test") + return gerror.New("test2") } func main() { diff --git a/geg/errors/gerror/gerror4.go b/geg/errors/gerror/gerror4.go new file mode 100644 index 000000000..8d7a7f015 --- /dev/null +++ b/geg/errors/gerror/gerror4.go @@ -0,0 +1,23 @@ +package main + +import ( + "fmt" + + "github.com/gogf/gf/g/errors/gerror" +) + +func OpenFile() error { + return gerror.New("permission denied") +} + +func OpenConfig() error { + return gerror.Wrap(OpenFile(), "configuration file opening failed") +} + +func ReadConfig() error { + return gerror.Wrap(OpenConfig(), "reading configuration failed") +} + +func main() { + fmt.Println(gerror.Cause(ReadConfig())) +} diff --git a/geg/errors/gerror/gerror5.go b/geg/errors/gerror/gerror5.go new file mode 100644 index 000000000..735b1ae1f --- /dev/null +++ b/geg/errors/gerror/gerror5.go @@ -0,0 +1,22 @@ +package main + +import ( + "errors" + + "github.com/gogf/gf/g/os/glog" + + "github.com/gogf/gf/g/errors/gerror" +) + +func Error1() error { + return errors.New("test1") +} + +func Error2() error { + return gerror.New("test2") +} + +func main() { + glog.Println(Error1()) + glog.Println(Error2()) +} diff --git a/geg/os/gmutex/gmutex_basic.go b/geg/os/gmutex/gmutex_basic.go new file mode 100644 index 000000000..4970db04a --- /dev/null +++ b/geg/os/gmutex/gmutex_basic.go @@ -0,0 +1,29 @@ +package main + +import ( + "time" + + "github.com/gogf/gf/g/os/glog" + "github.com/gogf/gf/g/os/gmutex" +) + +func main() { + mu := gmutex.New() + for i := 0; i < 10; i++ { + go func(n int) { + mu.Lock() + defer mu.Unlock() + glog.Println("Lock:", n) + time.Sleep(time.Second) + }(i) + } + for i := 0; i < 10; i++ { + go func(n int) { + mu.RLock() + defer mu.RUnlock() + glog.Println("RLock:", n) + time.Sleep(time.Second) + }(i) + } + time.Sleep(11 * time.Second) +} diff --git a/geg/os/gmutex/gmutex_func.go b/geg/os/gmutex/gmutex_func.go new file mode 100644 index 000000000..b0ed83c52 --- /dev/null +++ b/geg/os/gmutex/gmutex_func.go @@ -0,0 +1,22 @@ +package main + +import ( + "time" + + "github.com/gogf/gf/g/os/glog" + + "github.com/gogf/gf/g/os/gmutex" +) + +func main() { + mu := gmutex.New() + go mu.LockFunc(func() { + glog.Println("lock func1") + time.Sleep(1 * time.Second) + }) + time.Sleep(time.Millisecond) + go mu.LockFunc(func() { + glog.Println("lock func2") + }) + time.Sleep(2 * time.Second) +}