A barrier class?

486 views
Skip to first unread message

Travis Keep

unread,
May 13, 2016, 1:36:19 PM5/13/16
to golang-dev
Taking advanced OS at Georgia Tech, I learned about barriers, a synchronization primitive that forces threads to wait at the barrier until all threads have reached that barrier. The closest thing I know to a barrier is JAVA's CyclicBarrier class. I haven't found anything similar to CyclicBarrier in GO. sync.WaitGroup is close, but it isn't really a barrier because WaitGroup.Wait() doesn't reset the count automatically after releasing.

Does such a barrier abstraction exist in GO?

In a pinch, I rolled my own. This implementation isn't super per-formant but it does meet my needs. Would it be worth adding something like this to the go standard library?


































You can see my implementation here:

// barrier releases callers in groups of N and makes callers wait until
// there are N callers to release.
//
// If a caller happens to come in while the barrier is already releasing a
// group N callers, that caller waits until the barrier releases the next
// group of N callers.
type barrier struct {
        inCh  chan bool
        outCh chan bool
}

// newBarrier creates a new barrier. count is N.
func newBarrier(count int) *barrier {
        result := &barrier{inCh: make(chan bool), outCh: make(chan bool)}
        go result.loop(count)
        return result
}

// Await blocks the caller until there are N callers to release.
func (b *barrier) Await() {
        b.inCh <- true
        <-b.outCh
}

func (b *barrier) loop(count int) {
        for {
                for i := 0; i < count; i++ {
                        <-b.inCh
                }
                for i := 0; i < count; i++ {
                        b.outCh <- true
                }
        }
}


kennyl...@gmail.com

unread,
May 15, 2016, 1:20:56 PM5/15/16
to golang-dev
A sync.WaitGroup is a barrier, and serves the most common purpose where you make the WaitGroup, fire N goroutines and wait for their completion. It is meant to be thrown away, whereas Java's java.util.concurrent.CyclicBarrier is a reusable barrier for long-running threads. Due to goroutines (user-mode threads, "green threads", coroutines, ...) being much more lightweight than a true OS thread, you could simply dispose of the goroutines when they synchronize at the barrier, and fire N new goroutines with a new barrier.

If demand for a "CyclicBarrier" implementation shows up (or if you just want to share yours), I would suggest first throwing the implementation on something like Github, so that others can use it. It can always be added to the standard library later if the demand for it grows, and people agree that it is a necessity.

You should be able to make a better barrier with sync.Cond to wake up the blocked threads when the count is right. Unfortunately, not all the primitives used by WaitGroup are available to us (e.g., runtime.semacquire), so you'll have to use what you can find in sync and atomic. Using channels is certainly not the way to go here (but kudos for a creative solution).

Best regards,
Kenny

jtc...@gmail.com

unread,
May 15, 2016, 5:28:20 PM5/15/16
to golang-dev, kennyl...@gmail.com
A sync.Cond based barrier is pretty simple.

https://play.golang.org/p/dR3iNAQZrK
Reply all
Reply to author
Forward
0 new messages