go-ml.dev/pkg/base@v0.0.0-20200610162856-60c38abac71b/fu/counter.go (about) 1 package fu 2 3 import ( 4 "math" 5 "sync" 6 "sync/atomic" 7 ) 8 9 /* 10 WaitCounter implements barrier counter for lazy flow execution synchronization 11 */ 12 type WaitCounter struct { 13 Value uint64 14 cond sync.Cond 15 mu sync.Mutex 16 } 17 18 /* 19 Wait waits until counter Integer is not equal to specified index 20 */ 21 func (c *WaitCounter) Wait(index uint64) (r bool) { 22 r = true 23 if atomic.LoadUint64(&c.Value) == index { 24 // mostly when executes consequentially 25 return 26 } 27 c.mu.Lock() 28 if c.cond.L == nil { 29 c.cond.L = &c.mu 30 } 31 for c.Value != index { 32 if c.Value > index { 33 if c.Value == math.MaxUint64 { 34 r = false 35 break 36 } 37 panic("index continuity broken") 38 } 39 c.cond.Wait() 40 } 41 c.mu.Unlock() 42 return 43 } 44 45 /* 46 PostInc increments index and notifies waiting goroutines 47 */ 48 func (c *WaitCounter) Inc() (r bool) { 49 c.mu.Lock() 50 if c.cond.L == nil { 51 c.cond.L = &c.mu 52 } 53 if c.Value < math.MaxUint64 { 54 atomic.AddUint64(&c.Value, 1) 55 r = true 56 } 57 c.mu.Unlock() 58 c.cond.Broadcast() 59 return 60 } 61 62 /* 63 Stop sets Integer to ~uint64(0) and notifies waiting goroutines. It means also counter will not increment more 64 */ 65 func (c *WaitCounter) Stop() { 66 c.mu.Lock() 67 if c.cond.L == nil { 68 c.cond.L = &c.mu 69 } 70 atomic.StoreUint64(&c.Value, math.MaxUint64) 71 c.mu.Unlock() 72 c.cond.Broadcast() 73 } 74 75 /* 76 Stopped returns true if counter is stopped and will not increment more 77 */ 78 func (c *WaitCounter) Stopped() bool { 79 return atomic.LoadUint64(&c.Value) == math.MaxUint64 80 }