Правильно ли это использование атомного пакета golangs? - PullRequest
1 голос
/ 14 апреля 2019

У меня есть тип с двумя методами; 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
  }
  ...
}

1 Ответ

2 голосов
/ 14 апреля 2019

Это условие гонки, верно?

Если Close() вызывается одновременно с Add(), это действительно гонка данных.«Состояние гонки» является более общим термином, и атомные элементы предотвращают только гонки данных, а не все условия гонки.Определение одновременно основано на https://golang.org/ref/mem, но если нет никакой координации, и это делается из нескольких процедур, оно является параллельным.эта ситуация имеет смысл?

Строго говоря, вряд ли это будет иметь смысл.То, что вы написали, является гонкой данных бесплатно.Однако атомика хитрая.Например, если вы теперь добавите атомарный int64 в эту структуру, он будет иметь данные на машинах x86-32, поскольку они не выровнены по 64-битному типу, в то время как если вы сначала заказали int64, это не произойдет.Атомика может быть опасной и должна использоваться с особой осторожностью.

Или канал был бы более идиотским способом сделать это

Да!Вы также можете использовать sync.Mutex или даже sync.RWMutex.Атомика, если вы буквально не пишете реализацию sync.Mutex, является оптимизацией.Вы должны всегда избегать их в первой реализации.Если вы испытываете измеримую конкуренцию за блокировку, вы можете использовать атомарность.Просто будьте очень осторожны и осознайте, что есть все шансы испортить это.

...