Files
bl/common/utils/lockfree-1.1.3/blocks.go
昔念 269256a861 feat(common): 添加无锁并发工具包依赖
新增 lockfree-1.1.3 工具包到 go.work 文件中,为项目提供无锁并发数据结构支持,
提升高并发场景下的性能表现。
2025-12-05 00:36:28 +08:00

161 lines
3.5 KiB
Go
Raw Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

/*
* Copyright (C) THL A29 Limited, a Tencent company. All rights reserved.
*
* SPDX-License-Identifier: Apache-2.0
*
*/
package lockfree
import (
"runtime"
"sync"
"sync/atomic"
"time"
)
// blockStrategy 阻塞策略
type blockStrategy interface {
// block 阻塞
block(actual *uint64, expected uint64)
// release 释放阻塞
release()
}
// SchedBlockStrategy 调度等待策略
// 调用runtime.Gosched()方法使当前 g 主动让出 cpu 资源。
type SchedBlockStrategy struct {
}
func (s *SchedBlockStrategy) block(actual *uint64, expected uint64) {
runtime.Gosched()
}
func (s *SchedBlockStrategy) release() {
}
// SleepBlockStrategy 休眠等待策略
// 调用 Sleep 方法使当前 g 主动让出 cpu 资源。
// sleep poll 参考值:
// 轮询时长为 10us 时cpu 开销约 2-3% 左右。
// 轮询时长为 5us 时cpu 开销约在 10% 左右。
// 轮询时长小于 5us 时cpu 开销接近 100% 满载。
type SleepBlockStrategy struct {
t time.Duration
}
func NewSleepBlockStrategy(wait time.Duration) *SleepBlockStrategy {
return &SleepBlockStrategy{
t: wait,
}
}
func (s *SleepBlockStrategy) block(actual *uint64, expected uint64) {
time.Sleep(s.t)
}
func (s *SleepBlockStrategy) release() {
}
// ProcYieldBlockStrategy CPU空指令策略
type ProcYieldBlockStrategy struct {
cycle uint32
}
func NewProcYieldBlockStrategy(cycle uint32) *ProcYieldBlockStrategy {
return &ProcYieldBlockStrategy{
cycle: cycle,
}
}
func (s *ProcYieldBlockStrategy) block(actual *uint64, expected uint64) {
procyield(s.cycle)
}
func (s *ProcYieldBlockStrategy) release() {
}
// OSYieldBlockStrategy 操作系统调度策略
type OSYieldBlockStrategy struct {
}
func NewOSYieldWaitStrategy() *OSYieldBlockStrategy {
return &OSYieldBlockStrategy{}
}
func (s *OSYieldBlockStrategy) block(actual *uint64, expected uint64) {
osyield()
}
func (s *OSYieldBlockStrategy) release() {
}
// ChanBlockStrategy chan阻塞策略
type ChanBlockStrategy struct {
bc chan struct{}
b uint32
}
func NewChanBlockStrategy() *ChanBlockStrategy {
return &ChanBlockStrategy{
bc: make(chan struct{}),
}
}
func (s *ChanBlockStrategy) block(actual *uint64, expected uint64) {
// 0未阻塞1阻塞
if atomic.CompareAndSwapUint32(&s.b, 0, 1) {
// 设置成功的话,表示阻塞,需要进行二次判断
if atomic.LoadUint64(actual) == expected {
// 表示阻塞失败,因为结果是一致的,此处需要重新将状态调整回来
if atomic.CompareAndSwapUint32(&s.b, 1, 0) {
// 表示回调成功,直接退出即可
return
} else {
// 表示有其他协程release了则读取对应chan即可
<-s.bc
}
} else {
// 如果说结果不一致,则表示阻塞,等待被释放即可
<-s.bc
}
}
// 没有设置成功,不用关注
}
func (s *ChanBlockStrategy) release() {
if atomic.CompareAndSwapUint32(&s.b, 1, 0) {
// 表示可以释放即chan是等待状态
s.bc <- struct{}{}
}
// 无法设置则不用关心
return
}
// ConditionBlockStrategy condition 阻塞策略
type ConditionBlockStrategy struct {
cond *sync.Cond
}
func NewConditionBlockStrategy() *ConditionBlockStrategy {
return &ConditionBlockStrategy{
cond: sync.NewCond(&sync.Mutex{}),
}
}
func (s *ConditionBlockStrategy) block(actual *uint64, expected uint64) {
s.cond.L.Lock()
defer s.cond.L.Unlock()
if atomic.LoadUint64(actual) == expected {
return
}
s.cond.Wait()
}
func (s *ConditionBlockStrategy) release() {
s.cond.L.Lock()
defer s.cond.L.Unlock()
s.cond.Broadcast()
}