github.com/bruceshao/lockfree@v1.1.3-0.20230816090528-e89824c0a6e9/blocks.go (about) 1 /* 2 * Copyright (C) THL A29 Limited, a Tencent company. All rights reserved. 3 * 4 * SPDX-License-Identifier: Apache-2.0 5 * 6 */ 7 8 package lockfree 9 10 import ( 11 "runtime" 12 "sync" 13 "sync/atomic" 14 "time" 15 ) 16 17 // blockStrategy 阻塞策略 18 type blockStrategy interface { 19 // block 阻塞 20 block(actual *uint64, expected uint64) 21 22 // release 释放阻塞 23 release() 24 } 25 26 // SchedBlockStrategy 调度等待策略 27 // 调用runtime.Gosched()方法使当前 g 主动让出 cpu 资源。 28 type SchedBlockStrategy struct { 29 } 30 31 func (s *SchedBlockStrategy) block(actual *uint64, expected uint64) { 32 runtime.Gosched() 33 } 34 35 func (s *SchedBlockStrategy) release() { 36 } 37 38 // SleepBlockStrategy 休眠等待策略 39 // 调用 Sleep 方法使当前 g 主动让出 cpu 资源。 40 // sleep poll 参考值: 41 // 轮询时长为 10us 时,cpu 开销约 2-3% 左右。 42 // 轮询时长为 5us 时,cpu 开销约在 10% 左右。 43 // 轮询时长小于 5us 时,cpu 开销接近 100% 满载。 44 type SleepBlockStrategy struct { 45 t time.Duration 46 } 47 48 func NewSleepBlockStrategy(wait time.Duration) *SleepBlockStrategy { 49 return &SleepBlockStrategy{ 50 t: wait, 51 } 52 } 53 54 func (s *SleepBlockStrategy) block(actual *uint64, expected uint64) { 55 time.Sleep(s.t) 56 } 57 58 func (s *SleepBlockStrategy) release() { 59 } 60 61 // ProcYieldBlockStrategy CPU空指令策略 62 type ProcYieldBlockStrategy struct { 63 cycle uint32 64 } 65 66 func NewProcYieldBlockStrategy(cycle uint32) *ProcYieldBlockStrategy { 67 return &ProcYieldBlockStrategy{ 68 cycle: cycle, 69 } 70 } 71 72 func (s *ProcYieldBlockStrategy) block(actual *uint64, expected uint64) { 73 procyield(s.cycle) 74 } 75 76 func (s *ProcYieldBlockStrategy) release() { 77 } 78 79 // OSYieldBlockStrategy 操作系统调度策略 80 type OSYieldBlockStrategy struct { 81 } 82 83 func NewOSYieldWaitStrategy() *OSYieldBlockStrategy { 84 return &OSYieldBlockStrategy{} 85 } 86 87 func (s *OSYieldBlockStrategy) block(actual *uint64, expected uint64) { 88 osyield() 89 } 90 91 func (s *OSYieldBlockStrategy) release() { 92 } 93 94 // ChanBlockStrategy chan阻塞策略 95 type ChanBlockStrategy struct { 96 bc chan struct{} 97 b uint32 98 } 99 100 func NewChanBlockStrategy() *ChanBlockStrategy { 101 return &ChanBlockStrategy{ 102 bc: make(chan struct{}), 103 } 104 } 105 106 func (s *ChanBlockStrategy) block(actual *uint64, expected uint64) { 107 // 0:未阻塞;1:阻塞 108 if atomic.CompareAndSwapUint32(&s.b, 0, 1) { 109 // 设置成功的话,表示阻塞,需要进行二次判断 110 if atomic.LoadUint64(actual) == expected { 111 // 表示阻塞失败,因为结果是一致的,此处需要重新将状态调整回来 112 if atomic.CompareAndSwapUint32(&s.b, 1, 0) { 113 // 表示回调成功,直接退出即可 114 return 115 } else { 116 // 表示有其他协程release了,则读取对应chan即可 117 <-s.bc 118 } 119 } else { 120 // 如果说结果不一致,则表示阻塞,等待被释放即可 121 <-s.bc 122 } 123 } 124 // 没有设置成功,不用关注 125 } 126 127 func (s *ChanBlockStrategy) release() { 128 if atomic.CompareAndSwapUint32(&s.b, 1, 0) { 129 // 表示可以释放,即chan是等待状态 130 s.bc <- struct{}{} 131 } 132 // 无法设置则不用关心 133 return 134 } 135 136 // ConditionBlockStrategy condition 阻塞策略 137 type ConditionBlockStrategy struct { 138 cond *sync.Cond 139 } 140 141 func NewConditionBlockStrategy() *ConditionBlockStrategy { 142 return &ConditionBlockStrategy{ 143 cond: sync.NewCond(&sync.Mutex{}), 144 } 145 } 146 147 func (s *ConditionBlockStrategy) block(actual *uint64, expected uint64) { 148 s.cond.L.Lock() 149 defer s.cond.L.Unlock() 150 if atomic.LoadUint64(actual) == expected { 151 return 152 } 153 s.cond.Wait() 154 } 155 156 func (s *ConditionBlockStrategy) release() { 157 s.cond.L.Lock() 158 defer s.cond.L.Unlock() 159 s.cond.Broadcast() 160 }