mirror of
https://github.com/xiaoqidun/klock.git
synced 2026-09-03 08:30:22 +08:00
Compare commits
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
60204bcee6 | ||
|
|
5b5bca65b0 | ||
|
|
46a0acb476 |
No files matched your search
@@ -186,7 +186,7 @@
|
|||||||
same "printed page" as the copyright notice for easier
|
same "printed page" as the copyright notice for easier
|
||||||
identification within third-party archives.
|
identification within third-party archives.
|
||||||
|
|
||||||
Copyright 2025 肖其顿
|
Copyright 2025-2026 肖其顿 (XIAO QI DUN)
|
||||||
|
|
||||||
Licensed under the Apache License, Version 2.0 (the "License");
|
Licensed under the Apache License, Version 2.0 (the "License");
|
||||||
you may not use this file except in compliance with the License.
|
you may not use this file except in compliance with the License.
|
||||||
|
|||||||
@@ -1,13 +1,5 @@
|
|||||||
Copyright 2025 肖其顿
|
klock
|
||||||
|
Copyright 2025-2026 肖其顿 (XIAO QI DUN)
|
||||||
|
|
||||||
Licensed under the Apache License, Version 2.0 (the "License");
|
This product includes software developed by
|
||||||
you may not use this file except in compliance with the License.
|
肖其顿 (XIAO QI DUN) (https://github.com/xiaoqidun/klock).
|
||||||
You may obtain a copy of the License at
|
|
||||||
|
|
||||||
http://www.apache.org/licenses/LICENSE-2.0
|
|
||||||
|
|
||||||
Unless required by applicable law or agreed to in writing, software
|
|
||||||
distributed under the License is distributed on an "AS IS" BASIS,
|
|
||||||
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
|
||||||
See the License for the specific language governing permissions and
|
|
||||||
limitations under the License.
|
|
||||||
+1
-1
@@ -1,4 +1,4 @@
|
|||||||
// Copyright 2025 肖其顿
|
// Copyright 2025-2026 肖其顿 (XIAO QI DUN)
|
||||||
//
|
//
|
||||||
// Licensed under the Apache License, Version 2.0 (the "License");
|
// Licensed under the Apache License, Version 2.0 (the "License");
|
||||||
// you may not use this file except in compliance with the License.
|
// you may not use this file except in compliance with the License.
|
||||||
|
|||||||
@@ -1,3 +1,3 @@
|
|||||||
module github.com/xiaoqidun/klock
|
module github.com/xiaoqidun/klock
|
||||||
|
|
||||||
go 1.25.1
|
go 1.24.0
|
||||||
@@ -1,4 +1,4 @@
|
|||||||
// Copyright 2025 肖其顿
|
// Copyright 2025-2026 肖其顿 (XIAO QI DUN)
|
||||||
//
|
//
|
||||||
// Licensed under the Apache License, Version 2.0 (the "License");
|
// Licensed under the Apache License, Version 2.0 (the "License");
|
||||||
// you may not use this file except in compliance with the License.
|
// you may not use this file except in compliance with the License.
|
||||||
@@ -185,6 +185,7 @@ func (kl *KeyLock) TryLock(key string) bool {
|
|||||||
// LockWithTimeout 尝试在给定的时间内为指定的键获取写锁。
|
// LockWithTimeout 尝试在给定的时间内为指定的键获取写锁。
|
||||||
// 如果在超时前成功获取锁,则返回 true;否则返回 false。
|
// 如果在超时前成功获取锁,则返回 true;否则返回 false。
|
||||||
func (kl *KeyLock) LockWithTimeout(key string, timeout time.Duration) bool {
|
func (kl *KeyLock) LockWithTimeout(key string, timeout time.Duration) bool {
|
||||||
|
deadline := time.Now().Add(timeout)
|
||||||
le := kl.prepareLock(key)
|
le := kl.prepareLock(key)
|
||||||
// 立即尝试一次,以避免在锁可用时产生不必要的延迟。
|
// 立即尝试一次,以避免在锁可用时产生不必要的延迟。
|
||||||
if le.rw.TryLock() {
|
if le.rw.TryLock() {
|
||||||
@@ -197,17 +198,26 @@ func (kl *KeyLock) LockWithTimeout(key string, timeout time.Duration) bool {
|
|||||||
kl.cancelLock(key, le)
|
kl.cancelLock(key, le)
|
||||||
}
|
}
|
||||||
}()
|
}()
|
||||||
timer := time.NewTimer(timeout)
|
|
||||||
defer timer.Stop()
|
|
||||||
pollInterval := kl.config.InitialPollInterval
|
pollInterval := kl.config.InitialPollInterval
|
||||||
maxPollInterval := kl.config.MaxPollInterval
|
maxPollInterval := kl.config.MaxPollInterval
|
||||||
for {
|
for {
|
||||||
select {
|
remaining := time.Until(deadline)
|
||||||
case <-timer.C:
|
if remaining <= 0 {
|
||||||
return false
|
return false
|
||||||
default:
|
}
|
||||||
time.Sleep(pollInterval)
|
sleepInterval := pollInterval
|
||||||
|
if sleepInterval > remaining {
|
||||||
|
sleepInterval = remaining
|
||||||
|
}
|
||||||
|
time.Sleep(sleepInterval)
|
||||||
|
if time.Until(deadline) <= 0 {
|
||||||
|
return false
|
||||||
|
}
|
||||||
if le.rw.TryLock() {
|
if le.rw.TryLock() {
|
||||||
|
if time.Until(deadline) <= 0 {
|
||||||
|
le.rw.Unlock()
|
||||||
|
return false
|
||||||
|
}
|
||||||
kl.commitLock(key, le)
|
kl.commitLock(key, le)
|
||||||
acquired = true
|
acquired = true
|
||||||
return true
|
return true
|
||||||
@@ -218,7 +228,6 @@ func (kl *KeyLock) LockWithTimeout(key string, timeout time.Duration) bool {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
|
||||||
|
|
||||||
// RLock 为指定的键获取一个读锁。
|
// RLock 为指定的键获取一个读锁。
|
||||||
// 如果锁已被其他 goroutine 持有写锁,则此调用将阻塞直到锁可用。
|
// 如果锁已被其他 goroutine 持有写锁,则此调用将阻塞直到锁可用。
|
||||||
@@ -244,6 +253,7 @@ func (kl *KeyLock) TryRLock(key string) bool {
|
|||||||
// RLockWithTimeout 尝试在给定的时间内为指定的键获取读锁。
|
// RLockWithTimeout 尝试在给定的时间内为指定的键获取读锁。
|
||||||
// 如果在超时前成功获取锁,则返回 true;否则返回 false。
|
// 如果在超时前成功获取锁,则返回 true;否则返回 false。
|
||||||
func (kl *KeyLock) RLockWithTimeout(key string, timeout time.Duration) bool {
|
func (kl *KeyLock) RLockWithTimeout(key string, timeout time.Duration) bool {
|
||||||
|
deadline := time.Now().Add(timeout)
|
||||||
le := kl.prepareLock(key)
|
le := kl.prepareLock(key)
|
||||||
// 立即尝试一次
|
// 立即尝试一次
|
||||||
if le.rw.TryRLock() {
|
if le.rw.TryRLock() {
|
||||||
@@ -256,17 +266,26 @@ func (kl *KeyLock) RLockWithTimeout(key string, timeout time.Duration) bool {
|
|||||||
kl.cancelLock(key, le)
|
kl.cancelLock(key, le)
|
||||||
}
|
}
|
||||||
}()
|
}()
|
||||||
timer := time.NewTimer(timeout)
|
|
||||||
defer timer.Stop()
|
|
||||||
pollInterval := kl.config.InitialPollInterval
|
pollInterval := kl.config.InitialPollInterval
|
||||||
maxPollInterval := kl.config.MaxPollInterval
|
maxPollInterval := kl.config.MaxPollInterval
|
||||||
for {
|
for {
|
||||||
select {
|
remaining := time.Until(deadline)
|
||||||
case <-timer.C:
|
if remaining <= 0 {
|
||||||
return false
|
return false
|
||||||
default:
|
}
|
||||||
time.Sleep(pollInterval)
|
sleepInterval := pollInterval
|
||||||
|
if sleepInterval > remaining {
|
||||||
|
sleepInterval = remaining
|
||||||
|
}
|
||||||
|
time.Sleep(sleepInterval)
|
||||||
|
if time.Until(deadline) <= 0 {
|
||||||
|
return false
|
||||||
|
}
|
||||||
if le.rw.TryRLock() {
|
if le.rw.TryRLock() {
|
||||||
|
if time.Until(deadline) <= 0 {
|
||||||
|
le.rw.RUnlock()
|
||||||
|
return false
|
||||||
|
}
|
||||||
kl.commitLock(key, le)
|
kl.commitLock(key, le)
|
||||||
acquired = true
|
acquired = true
|
||||||
return true
|
return true
|
||||||
@@ -277,7 +296,6 @@ func (kl *KeyLock) RLockWithTimeout(key string, timeout time.Duration) bool {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
|
||||||
|
|
||||||
// Unlock 释放指定键的写锁。
|
// Unlock 释放指定键的写锁。
|
||||||
// 如果对未锁定的键调用 Unlock,将会引发 panic。
|
// 如果对未锁定的键调用 Unlock,将会引发 panic。
|
||||||
|
|||||||
+49
-1
@@ -1,4 +1,4 @@
|
|||||||
// Copyright 2025 肖其顿
|
// Copyright 2025-2026 肖其顿 (XIAO QI DUN)
|
||||||
//
|
//
|
||||||
// Licensed under the Apache License, Version 2.0 (the "License");
|
// Licensed under the Apache License, Version 2.0 (the "License");
|
||||||
// you may not use this file except in compliance with the License.
|
// you may not use this file except in compliance with the License.
|
||||||
@@ -250,6 +250,30 @@ func TestLockWithTimeout(t *testing.T) {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// TestLockWithTimeoutDoesNotAcquireAfterDeadline 测试写锁在超时后被释放时不会再被获取。
|
||||||
|
func TestLockWithTimeoutDoesNotAcquireAfterDeadline(t *testing.T) {
|
||||||
|
kl := NewWithConfig(Config{
|
||||||
|
MaxPollInterval: 50 * time.Millisecond,
|
||||||
|
InitialPollInterval: 50 * time.Millisecond,
|
||||||
|
})
|
||||||
|
key := "test_key"
|
||||||
|
released := make(chan struct{})
|
||||||
|
kl.Lock(key)
|
||||||
|
go func() {
|
||||||
|
time.Sleep(20 * time.Millisecond)
|
||||||
|
kl.Unlock(key)
|
||||||
|
close(released)
|
||||||
|
}()
|
||||||
|
acquired := kl.LockWithTimeout(key, 10*time.Millisecond)
|
||||||
|
if acquired {
|
||||||
|
kl.Unlock(key)
|
||||||
|
}
|
||||||
|
<-released
|
||||||
|
if acquired {
|
||||||
|
t.Fatal("LockWithTimeout 不应该在超时后获取锁")
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
// TestRLockWithTimeout 测试带超时的读锁获取功能。
|
// TestRLockWithTimeout 测试带超时的读锁获取功能。
|
||||||
func TestRLockWithTimeout(t *testing.T) {
|
func TestRLockWithTimeout(t *testing.T) {
|
||||||
kl := New()
|
kl := New()
|
||||||
@@ -270,6 +294,30 @@ func TestRLockWithTimeout(t *testing.T) {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// TestRLockWithTimeoutDoesNotAcquireAfterDeadline 测试读锁在超时后被释放时不会再被获取。
|
||||||
|
func TestRLockWithTimeoutDoesNotAcquireAfterDeadline(t *testing.T) {
|
||||||
|
kl := NewWithConfig(Config{
|
||||||
|
MaxPollInterval: 50 * time.Millisecond,
|
||||||
|
InitialPollInterval: 50 * time.Millisecond,
|
||||||
|
})
|
||||||
|
key := "test_key"
|
||||||
|
released := make(chan struct{})
|
||||||
|
kl.Lock(key)
|
||||||
|
go func() {
|
||||||
|
time.Sleep(20 * time.Millisecond)
|
||||||
|
kl.Unlock(key)
|
||||||
|
close(released)
|
||||||
|
}()
|
||||||
|
acquired := kl.RLockWithTimeout(key, 10*time.Millisecond)
|
||||||
|
if acquired {
|
||||||
|
kl.RUnlock(key)
|
||||||
|
}
|
||||||
|
<-released
|
||||||
|
if acquired {
|
||||||
|
t.Fatal("RLockWithTimeout 不应该在超时后获取锁")
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
// TestPanicOnUnlockOfUnlockedKey 测试对未锁定的键执行 Unlock 操作是否会引发 panic。
|
// TestPanicOnUnlockOfUnlockedKey 测试对未锁定的键执行 Unlock 操作是否会引发 panic。
|
||||||
func TestPanicOnUnlockOfUnlockedKey(t *testing.T) {
|
func TestPanicOnUnlockOfUnlockedKey(t *testing.T) {
|
||||||
defer func() {
|
defer func() {
|
||||||
|
|||||||
Reference in New Issue
Block a user