github.com/puellanivis/breton@v0.2.16/lib/sync/edge/edge.go (about) 1 // Package edge implements a simple atomic up/down edge/condition-change detector. 2 // 3 // When in the Down state, only the first call in any series of calls to Up will return true. 4 // When in the Up state, only the first call in any series of calls to Down will return true. 5 // 6 // So, after Up has been called at least once, only the first Down will return true, and vice-versa. 7 // 8 // Usage is pretty basic: 9 // 10 // // a zero-value Edge starts in state Down 11 // var e edge.Edge 12 // 13 // var wg sync.WaitGroup 14 // wg.Add(len(values)) 15 // 16 // for _, val := range values { 17 // val := val // shadow this value to loop-scope for the goroutine. 18 // 19 // go func(){ 20 // defer wg.Done() 21 // 22 // if someTestDoneInParallel(val) { 23 // if e.Up() { 24 // fmt.Println("called at most once") 25 // } 26 // } 27 // }() 28 // } 29 // 30 // wg.Wait() 31 // 32 // if e.Up() { 33 // fmt.Println("called if and only if e.Up was not called") 34 // } 35 // 36 // The functionality of Down is symmetric to Up. 37 // 38 // This is also useful for marking a data-set as dirty, while only locking 39 // individual data elements: 40 // 41 // var dirty edge.Edge 42 // t := time.NewTicker(5 * time.Second) 43 // 44 // go func() { 45 // for range t.C { 46 // if dirty.Down() { 47 // lockAndCommitDataSet() 48 // } 49 // } 50 // }() 51 package edge // import "github.com/puellanivis/breton/lib/sync/edge" 52 53 import ( 54 "sync/atomic" 55 ) 56 57 // Edge defines a synchronization object that defines two states Up and Down 58 type Edge struct { 59 // hide this value from callers, so that they cannot manipulate it. 60 e int32 61 } 62 63 var states = []string{"down", "up"} 64 65 // String returns a momentary state of the Edge. 66 func (e *Edge) String() string { 67 v := atomic.LoadInt32(&e.e) 68 return states[v] 69 } 70 71 // Up will ensure that the Edge is in state Up, and returns true only if state changed. 72 func (e *Edge) Up() bool { 73 return atomic.CompareAndSwapInt32(&e.e, 0, 1) 74 } 75 76 // Down will ensure that the Edge is in state Down, and returns true only if state changed. 77 func (e *Edge) Down() bool { 78 return atomic.CompareAndSwapInt32(&e.e, 1, 0) 79 }