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