github.com/rolandhe/saber@v0.0.4/gocc/condtimeout.go (about) 1 // code from https://gist.github.com/zviadm/c234426882bfc8acba88f3503edaaa36#file-cond2-go 2 3 package gocc 4 5 import ( 6 "sync" 7 "sync/atomic" 8 "time" 9 "unsafe" 10 ) 11 12 // Condition 支持wait timeout的同步条件 13 type Condition interface { 14 // Wait 同Cond Wait, 等待直到被唤醒 15 Wait() 16 // WaitWithTimeout , 带有超时的等待 17 WaitWithTimeout(t time.Duration) 18 // Broadcast 同Cond Broadcast 19 Broadcast() 20 // Signal 同Cond Signal 21 Signal() 22 } 23 24 // NewCondTimeout 构建支持timeout的cond 25 func NewCondTimeout(l sync.Locker) Condition { 26 c := &condTimeout{locker: l} 27 n := make(chan struct{}) 28 c.n = unsafe.Pointer(&n) 29 return c 30 } 31 32 // NewCondTimeoutWithName 构建Condition,可以指定名字, 日志输出是带有名字,方便排查问题 33 func NewCondTimeoutWithName(l sync.Locker, name string) Condition { 34 c := &condTimeout{locker: l, name: name} 35 n := make(chan struct{}) 36 c.n = unsafe.Pointer(&n) 37 return c 38 } 39 40 type condTimeout struct { 41 locker sync.Locker 42 n unsafe.Pointer 43 name string 44 } 45 46 // Wait Waits for Broadcast calls. Similar to regular sync.Cond, this unlocks the underlying 47 // locker first, waits on changes and re-locks it before returning. 48 func (c *condTimeout) Wait() { 49 n := c.NotifyChan() 50 c.locker.Unlock() 51 <-n 52 c.locker.Lock() 53 } 54 55 // WaitWithTimeout Same as Wait() call, but will only wait up to a given timeout. 56 func (c *condTimeout) WaitWithTimeout(t time.Duration) { 57 n := c.NotifyChan() 58 c.locker.Unlock() 59 60 select { 61 case <-n: 62 case <-time.After(t): 63 CcLogger.Info("name:%s,wait with timeout\n", c.name) 64 } 65 c.locker.Lock() 66 } 67 68 // NotifyChan Returns a channel that can be used to wait for next Broadcast() call. 69 func (c *condTimeout) NotifyChan() chan struct{} { 70 ptr := atomic.LoadPointer(&c.n) 71 return *((*chan struct{})(ptr)) 72 } 73 74 // Broadcast call notifies everyone that something has changed. 75 func (c *condTimeout) Broadcast() { 76 n := make(chan struct{}) 77 ptrOld := atomic.SwapPointer(&c.n, unsafe.Pointer(&n)) 78 close(*(*chan struct{})(ptrOld)) 79 } 80 81 func (c *condTimeout) Signal() { 82 n := c.NotifyChan() 83 select { 84 case n <- struct{}{}: 85 default: 86 } 87 }