github.com/songzhibin97/gkit@v1.2.13/internal/sys/mutex/recursive_mutex.go (about)

     1  package mutex
     2  
     3  import (
     4  	"fmt"
     5  	"sync"
     6  	"sync/atomic"
     7  
     8  	"github.com/songzhibin97/gkit/internal/sys/goid"
     9  )
    10  
    11  // RecursiveMutex 包装一个Mutex,实现可重入
    12  type RecursiveMutex struct {
    13  	sync.Mutex
    14  	owner     int64 // 当前持有锁的goroutine id
    15  	recursion int32 // 这个goroutine 重入的次数
    16  }
    17  
    18  func (m *RecursiveMutex) Lock() {
    19  	gid := goid.GetGID()
    20  	// 如果当前持有锁的goroutine就是这次调用的goroutine,说明是重入
    21  	if atomic.LoadInt64(&m.owner) == gid {
    22  		m.recursion++
    23  		return
    24  	}
    25  	m.Mutex.Lock()
    26  	// 获得锁的goroutine第一次调用,记录下它的goroutine id,调用次数加1
    27  	atomic.StoreInt64(&m.owner, gid)
    28  	m.recursion = 1
    29  }
    30  
    31  func (m *RecursiveMutex) Unlock() {
    32  	gid := goid.GetGID()
    33  	// 非持有锁的goroutine尝试释放锁,错误的使用
    34  	if atomic.LoadInt64(&m.owner) != gid {
    35  		panic(fmt.Sprintf("wrong the owner(%d): %d!", m.owner, gid))
    36  	}
    37  	// 调用次数减1
    38  	m.recursion--
    39  	if m.recursion != 0 { // 如果这个goroutine还没有完全释放,则直接返回
    40  		return
    41  	}
    42  	// 此goroutine最后一次调用,需要释放锁
    43  	atomic.StoreInt64(&m.owner, -1)
    44  	m.Mutex.Unlock()
    45  }