lei*_*lin 5 concurrency synchronization thread-safety go
我有结构与count属性需要线程安全访问.
我知道它可以用sync.Mutex或完成sync.RWMutex.但我不确定它是这样的:
type Status struct {
count uint32
attr1 string
attr2 string
}
func (s *Status) Get() uint32 {
return atomic.LoadUint32(&s.count)
}
func (s *Status) Add(n uint32) {
atomic.AddUint32(&s.count, n)
}
func (s *Status) Reset(n uint32) {
atomic.StoreUint32(&s.count, n)
}
Run Code Online (Sandbox Code Playgroud)
谢谢.
编辑:
我很困惑,直接访问字段s.count是不安全的.但是atomic.LoadUint32(&s.count)安全吗?
是的,如果只有这 3 个方法访问该count字段,您的解决方案就可以安全地从多个 goroutine 中同时使用。
Status.Get()但请注意,当您尝试使用它时,返回的值可能已经“过时”。例如:
s := &Status{}
if s.Get() == 3 {
fmt.Println(s.Get()) // This may or may not print 3
}
// Or
c := s.Get()
fmt.Println(c == s.Get()) // This may or may not print true
Run Code Online (Sandbox Code Playgroud)
上面的示例可能会打印3,也可能不会打印,true因为第二次调用s.Get()可能会在另一个 goroutine 中再次调用s.Add()。
Status.count如果您需要保证在对字段执行进一步计算时没有其他人修改或访问该字段的值,那么sync.Mutex或是可行的方法,因为您可以在完成计算时sync.RWMutex锁定该字段。count
编辑:回答您的编辑:
直接访问s.count不安全,atomic.LoadUint32(&s.count)才是安全。这样做的原因是,如果 goroutine #1 调用s.Add(),并且 goroutine #2 尝试访问s.count,则不能保证 goroutine #2 会看到 #1 所做的更改。在 #2 中,您可能只看到s.count.
如果没有显式同步,您无法保证观察到另一个 Goroutine 中变量的更改。直接访问s.count是一种非同步访问。使用通道或其他同步原语(例如sync或sync/atomic包)可确保对 的序列化访问s.count,因此这些解决方案将始终看到当前的更新值。
详细内容请参见这篇文章:Go内存模型