У меня есть тип с двумя методами; Add
& Close
. Доступ к методу Add
осуществляется одновременно, и он должен проверять, был ли когда-либо вызван Close
.
type foo struct {
closed bool
}
func (f *foo) Close() error {
f.closed = true
...
}
func (f *foo) Add(...) error {
if f.closed {
return ErrClosed
}
...
}
Это условие гонки, верно?
Так имеет ли смысл использование атомарного хранилища / загрузки в этой ситуации?
type foo struct {
closed int32
}
func (f *foo) Close() error {
atomic.StoreInt32(&f.closed, 1)
...
}
func (f *foo) Add(...) error {
if atomic.LoadInt32(&f.closed) == 1 {
return ErrClosed
}
...
}
Или канал будет более идиоматическим способом сделать это:
type foo struct {
closed chan struct{}
}
func NewFoo() *foo {
return &foo{make(chan struct{})}
}
func (f *foo) isClosed() bool {
select {
case <-f.closed:
return true
default:
}
return false
}
func (f *foo) Close() error {
close(f.closed)
...
}
func (f *foo) Add(...) error {
if f.isClosed() {
return ErrClosed
}
...
}
EDIT:
Спасибо за комментарии, я закончил с этим.
type foo struct {
closed bool
closeLock sync.RWMutex
}
func (f *foo) Close() error {
f.closeLock.Lock()
defer f.closeLock.Unlock()
f.closed = true
...
}
func (f *foo) Add(...) error {
f.closeLock.RLock()
defer f.closeLock.RUnlock()
if f.closed {
return ErrClosed
}
...
}