[feat] package nazasync:新增的package,其中的Mutex可用于debug锁方面的问题

pull/2/head
q191201771 4 years ago
parent 90b29a0b9e
commit a24a0d5d7f

@ -0,0 +1,33 @@
// Copyright 2021, Chef. All rights reserved.
// https://github.com/q191201771/naza
//
// Use of this source code is governed by a MIT-style license
// that can be found in the License file.
//
// Author: Chef (191201771@qq.com)
package nazasync
import (
"bytes"
"errors"
"runtime"
"strconv"
)
// NOTICE copy from https://github.com/golang/net/blob/master/http2/gotrack.go
var ErrObtainGoroutineID = errors.New("nazasync: obtain current goroutine id failed")
func CurGoroutineID() (int64, error) {
var goroutineSpace = []byte("goroutine ")
b := make([]byte, 128)
b = b[:runtime.Stack(b, false)]
b = bytes.TrimPrefix(b, goroutineSpace)
i := bytes.IndexByte(b, ' ')
if i < 0 {
return -1, ErrObtainGoroutineID
}
return strconv.ParseInt(string(b[:i]), 10, 64)
}

@ -0,0 +1,40 @@
// Copyright 2021, Chef. All rights reserved.
// https://github.com/q191201771/naza
//
// Use of this source code is governed by a MIT-style license
// that can be found in the License file.
//
// Author: Chef (191201771@qq.com)
package nazasync
import (
"sync"
"testing"
"github.com/q191201771/naza/pkg/assert"
"github.com/q191201771/naza/pkg/nazalog"
)
func TestCurGoroutineID(t *testing.T) {
max := 5
gid, err := CurGoroutineID()
assert.Equal(t, nil, err)
nazalog.Infof("> main. gid=%d", gid)
var wg sync.WaitGroup
wg.Add(max)
for i := 0; i < max; i++ {
go func(ii int) {
gid, err := CurGoroutineID()
assert.Equal(t, nil, err)
nazalog.Infof("> %d. gid=%d", ii, gid)
wg.Done()
}(i)
}
wg.Wait()
gid, err = CurGoroutineID()
assert.Equal(t, nil, err)
nazalog.Infof("< main. gid=%d", gid)
}

@ -0,0 +1,67 @@
// Copyright 2021, Chef. All rights reserved.
// https://github.com/q191201771/naza
//
// Use of this source code is governed by a MIT-style license
// that can be found in the License file.
//
// Author: Chef (191201771@qq.com)
package nazasync
import (
"fmt"
"sync"
"github.com/q191201771/naza/pkg/unique"
"github.com/q191201771/naza/pkg/nazalog"
)
// 用于debug锁方面的问题
const unlockedGid = 0
type Mutex struct {
core sync.Mutex
mu sync.Mutex
uniqueKey string
gid int64
}
func (m *Mutex) Lock() {
m.mu.Lock()
if m.uniqueKey == "" {
m.uniqueKey = unique.GenUniqueKey("MUTEX")
}
gid, _ := CurGoroutineID()
if gid == m.gid {
nazalog.Out(nazalog.LevelError, 3, fmt.Sprintf("[%s] recursive lock. gid=%d", m.uniqueKey, gid))
}
m.gid = gid
m.mu.Unlock()
nazalog.Out(nazalog.LevelDebug, 3, fmt.Sprintf("[%s] > Lock(). gid=%d", m.uniqueKey, gid))
m.core.Lock()
nazalog.Out(nazalog.LevelDebug, 3, fmt.Sprintf("[%s] < Lock(). gid=%d", m.uniqueKey, gid))
}
func (m *Mutex) Unlock() {
m.mu.Lock()
gid, _ := CurGoroutineID()
if gid != m.gid {
if m.gid == unlockedGid {
nazalog.Out(nazalog.LevelError, 3,
fmt.Sprintf("[%s] unlock of unlocked mutex. lock gid=%d, unlock gid=%d", m.uniqueKey, m.gid, gid))
} else {
nazalog.Out(nazalog.LevelError, 3,
fmt.Sprintf("[%s] mismatched unlock. lock gid=%d, unlock gid=%d", m.uniqueKey, m.gid, gid))
}
}
m.gid = unlockedGid
m.mu.Unlock()
nazalog.Out(nazalog.LevelDebug, 3, fmt.Sprintf("[%s] > Unlock(). gid=%d", m.uniqueKey, gid))
m.core.Unlock()
nazalog.Out(nazalog.LevelDebug, 3, fmt.Sprintf("[%s] < Unlock(). gid=%d", m.uniqueKey, gid))
}

@ -0,0 +1,44 @@
// Copyright 2021, Chef. All rights reserved.
// https://github.com/q191201771/naza
//
// Use of this source code is governed by a MIT-style license
// that can be found in the License file.
//
// Author: Chef (191201771@qq.com)
package nazasync
import "testing"
func TestMutex(t *testing.T) {
var mu Mutex
mu.Lock()
mu.Unlock()
ch := make(chan struct{}, 1)
go func() {
mu.Lock()
mu.Unlock()
ch <- struct{}{}
}()
<-ch
}
func TestMutex_Corner(t *testing.T) {
//var mu Mutex
// case1 递归
//mu.Lock()
//mu.Lock()
// case2 先UnLock
//mu.Unlock()
// case3 协程1Lock协程2Unlock
//mu.Lock()
//ch := make(chan struct{}, 1)
//ch <- struct{}{}
//go func() {
// <-ch
// mu.Unlock()
//}()
//time.Sleep(200 * time.Millisecond)
}
Loading…
Cancel
Save