
7 changed files with 85 additions and 25 deletions
@ -0,0 +1,33 @@
|
||||
package signal |
||||
|
||||
import ( |
||||
"sync" |
||||
) |
||||
|
||||
// Signal lets goroutines signal that some event has occurred. Other goroutines can wait for the signal.
|
||||
type Signal struct { |
||||
ch chan struct{} |
||||
once sync.Once |
||||
} |
||||
|
||||
// New wraps a channel and turns it into a signal for a one-time event.
|
||||
func New(ch chan struct{}) *Signal { |
||||
return &Signal{ |
||||
ch: ch, |
||||
once: sync.Once{}, |
||||
} |
||||
} |
||||
|
||||
// Notify alerts any goroutines waiting on this signal that the event has occurred.
|
||||
// After the first call to Notify(), future calls are no-op.
|
||||
func (s *Signal) Notify() { |
||||
s.once.Do(func() { |
||||
close(s.ch) |
||||
}) |
||||
} |
||||
|
||||
// Wait returns a channel which will be written to when Notify() is called for the first time.
|
||||
// This channel will never be written to a second time.
|
||||
func (s *Signal) Wait() <-chan struct{} { |
||||
return s.ch |
||||
} |
@ -0,0 +1,25 @@
|
||||
package signal |
||||
|
||||
import ( |
||||
"testing" |
||||
) |
||||
|
||||
func TestMultiNotifyDoesntCrash(t *testing.T) { |
||||
sig := New(make(chan struct{})) |
||||
sig.Notify() |
||||
sig.Notify() |
||||
// If code has reached here without crashing, the test has passed.
|
||||
} |
||||
|
||||
func TestWait(t *testing.T) { |
||||
sig := New(make(chan struct{})) |
||||
sig.Notify() |
||||
select { |
||||
case <-sig.Wait(): |
||||
// Test succeeds
|
||||
return |
||||
default: |
||||
// sig.Wait() should have been read from, because sig.Notify() wrote to it.
|
||||
t.Fail() |
||||
} |
||||
} |
Loading…
Reference in new issue