dounei9043 2019-04-13 21:29
浏览 69
已采纳

golangs原子包的这种用法正确吗?

I have a type with two methods; Add & Close. The Add method is accessed concurrently and it should check if Close was ever called.

type foo struct {
  closed bool
}

func (f *foo) Close() error {
 f.closed = true
  ...
}

func (f *foo) Add(...) error {
  if f.closed {
    return ErrClosed
  }
  ...
}

This is a race condition right?

So would using an atomic store/load in this situation make sense?

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
  }
  ...
}

Or would a channel be a more idiomatic way to do this:

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:

Thank you for the comments, I ended up with this.

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条回答 默认 最新

  • douhuanqiao5290 2019-04-13 21:58
    关注

    This is a race condition right?

    If Close() is being called concurrently with Add(), it is indeed a data race. "Race condition" is a more general term and atomics only prevent data races, not all race conditions. The definition of concurrently is based on https://golang.org/ref/mem but if there is no coordination and it is being done from multiple goroutines, it is concurrent.

    So would using an atomic store/load in this situation make sense?

    Strictly speaking, it is unlikely it would make sense. What you have written is data race free. However, atomics are tricky. For example, if you now added an atomic int64 to this struct, it would have dataraces on x86-32 machines for not being 64 bit aligned while if you ordered the int64 first it wouldn't. Atomics can be dangerous and should be used with extreme caution.

    Or would a channel be a more idomatic way to do this

    Yes! You can also use a sync.Mutex or even sync.RWMutex. Atomics, unless you are literally writing the sync.Mutex implementation, are an optimization. You should always avoid them in a first implementation. If you are having measurable lock contention, you can then look into using atomics. Just be very careful and realize that there is a good chance of messing it up.

    本回答被题主选为最佳回答 , 对您是否有帮助呢?
    评论

报告相同问题?

悬赏问题

  • ¥15 程序不包含适用于入口点的静态Main方法
  • ¥15 素材场景中光线烘焙后灯光失效
  • ¥15 请教一下各位,为什么我这个没有实现模拟点击
  • ¥15 执行 virtuoso 命令后,界面没有,cadence 启动不起来
  • ¥50 comfyui下连接animatediff节点生成视频质量非常差的原因
  • ¥20 有关区间dp的问题求解
  • ¥15 多电路系统共用电源的串扰问题
  • ¥15 slam rangenet++配置
  • ¥15 有没有研究水声通信方面的帮我改俩matlab代码
  • ¥15 ubuntu子系统密码忘记