util: Improve the sync primitives.

This commit is contained in:
James Shubin
2019-02-20 12:37:04 -05:00
parent ccad6e7e1a
commit 463ba23003

View File

@@ -52,7 +52,8 @@ type EasyOnce struct {
once *sync.Once once *sync.Once
} }
// Done runs the function which was defined in `Func` a maximum of once. // Done runs the function which was defined in `Func` a maximum of once. Please
// note that this is not currently thread-safe. Wrap calls to this with a mutex.
func (obj *EasyOnce) Done() { func (obj *EasyOnce) Done() {
if obj.once == nil { if obj.once == nil {
// we must initialize it! // we must initialize it!
@@ -66,22 +67,27 @@ func (obj *EasyOnce) Done() {
// EasyExit is a struct that helps you build a close switch and signal which can // EasyExit is a struct that helps you build a close switch and signal which can
// be called multiple times safely, and used as a signal many times in parallel. // be called multiple times safely, and used as a signal many times in parallel.
type EasyExit struct { type EasyExit struct {
exit chan struct{} mutex *sync.Mutex
once *sync.Once exit chan struct{}
err error once *sync.Once
err error
} }
// NewEasyExit builds an easy exit struct. // NewEasyExit builds an easy exit struct.
func NewEasyExit() *EasyExit { func NewEasyExit() *EasyExit {
return &EasyExit{ return &EasyExit{
exit: make(chan struct{}), mutex: &sync.Mutex{},
once: &sync.Once{}, exit: make(chan struct{}),
once: &sync.Once{},
} }
} }
// Done triggers the exit signal. It associates an error condition with it too. // Done triggers the exit signal. It associates an error condition with it too.
// This is thread-safe.
func (obj *EasyExit) Done(err error) { func (obj *EasyExit) Done(err error) {
if obj.once == nil { obj.mutex.Lock()
defer obj.mutex.Unlock()
if obj.once == nil { // redundant
// we must initialize it! // we must initialize it!
obj.once = &sync.Once{} obj.once = &sync.Once{}
} }
@@ -94,7 +100,7 @@ func (obj *EasyExit) Done(err error) {
// Signal returns the channel that we watch for the exit signal on. It will // Signal returns the channel that we watch for the exit signal on. It will
// close to signal us when triggered by Exit(). // close to signal us when triggered by Exit().
func (obj *EasyExit) Signal() chan struct{} { func (obj *EasyExit) Signal() <-chan struct{} {
return obj.exit return obj.exit
} }