Golang 實現帶過期時間的單機鎖
單機鎖要實現的目標:
-
加鎖:會記錄一個鎖的擁有者
owner -
解鎖:只有鎖的擁有者才能解鎖
-
如果有設定鎖的超時時間,到時間自動解鎖(避免忘記解鎖)
代碼很簡單,直接貼源碼。相信聰明的你一看就懂
項目地址: https://github.com/gofish2020/expiredlock
package expiredlock
import (
"bytes"
"context"
"fmt"
"os"
"runtime"
"strconv"
"sync"
"time"
)
/*
實現一個帶自動過期時間的單機鎖
只有鎖的擁有者才能解鎖
*/
type ExpiredLocker struct {
mutex sync.Mutex // 單機鎖
processMutex sync.Mutex // 保護下面的字段
owner string// 鎖的擁有者(用進程id+協程id作爲擁有者身份標記)
cancel context.CancelFunc //取消函數(讓協程停止)
}
func (l *ExpiredLocker) Lock(expireTime time.Duration) {
// 加鎖
l.mutex.Lock()
l.processMutex.Lock()
defer l.processMutex.Unlock()
// 加鎖成功的唯一標識
l.owner = getPidGid()
if expireTime <= 0 { // 如果沒有過期時間,說明不需要創建帶過期時間的鎖
return
}
ctx, cancel := context.WithTimeout(context.Background(), expireTime)
l.cancel = cancel
gofunc() {
<-ctx.Done()
if ctx.Err() == context.DeadlineExceeded { // 過期取消
l.unlocker(l.owner)
}
}()
}
func (l *ExpiredLocker) UnLock() {
l.unlocker(getPidGid()) // 用戶主動調用解鎖(監視過期的協程,如果有啓動,需主動取消掉)
}
func (l *ExpiredLocker) unlocker(owner string) {
l.processMutex.Lock()
defer l.processMutex.Unlock()
// 必須是鎖的擁有者
if l.owner != "" && l.owner == owner {
l.owner = ""
if l.cancel != nil { // 說明是帶過期時間的鎖
l.cancel() // 目的讓協程也停止
l.cancel = nil
}
l.mutex.Unlock() // 解鎖
}
}
// 進程id + 協程id 作爲唯一標識
func getPidGid() string {
b := make([]byte, 64)
b = b[:runtime.Stack(b, false)]
b = bytes.TrimPrefix(b, []byte("goroutine "))
b = b[:bytes.IndexByte(b, ' ')]
n, _ := strconv.ParseUint(string(b), 10, 64)
return fmt.Sprintf("%d_%d", os.Getpid(), n)
}
本文由 Readfog 進行 AMP 轉碼,版權歸原作者所有。
來源:https://mp.weixin.qq.com/s/Z7NTf9HnwmZ3avoGUlRlYA