161 lines
3.5 KiB
Go
161 lines
3.5 KiB
Go
/*
|
||
* 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()
|
||
}
|