goexpirelock/blocklock.go
2025-04-18 09:47:46 +08:00

76 lines
1.0 KiB
Go

package expirelock
import (
"context"
"errors"
"expirelock/os"
"sync"
"sync/atomic"
"time"
)
type Block struct {
token atomic.Value
mu sync.Mutex
dmu sync.Mutex
celFu context.CancelFunc
}
func NewBlock() *Block {
return &Block{}
}
func (b *Block) Lock(ttl time.Duration) error {
b.mu.Lock()
b.dmu.Lock()
defer b.dmu.Unlock()
token := os.GetCurrentProcessAndGogroutineIDStr()
b.token.Store(token)
b.celFu = nil
if ttl <= 0 {
return nil
}
var ctx context.Context
ctx, b.celFu = context.WithCancel(context.Background())
go func() {
select {
case <-ctx.Done():
return
case <-time.After(ttl):
_ = b.unlock(token)
}
}()
return nil
}
func (b *Block) unlock(token string) error {
b.dmu.Lock()
defer b.dmu.Unlock()
id, _ := b.token.Load().(string)
if id != token {
return errors.New("invalid token")
}
if b.celFu != nil {
b.celFu()
}
b.token.Store("")
b.mu.Unlock()
return nil
}
func (b *Block) Unlock() error {
token := os.GetCurrentProcessAndGogroutineIDStr()
return b.unlock(token)
}