Files
bl/common/utils/lockfree-1.1.3/blocks.go

161 lines
3.5 KiB
Go
Raw Normal View History

/*
* 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()
}