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  }