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  }