我在 Go 中实现了以下计数器,我想同时使用它。我正在使用 atomic 包来存储状态,但不确定是否会遇到任何竞争条件。例如,我是否还需要添加一个额外的互斥锁以防止增量低于零,或者原子操作是否提供足够的安全性?谢谢!
type Counter struct {
counter uint64
finished uint32
sync.Mutex
}
// Inc increments the counter by one
func (c *Counter) Inc() error {
if c.isFinished() {
return fmt.Errorf("counter is finished")
}
atomic.AddUint64(&c.counter, 1)
return nil
}
// Dec decrements the counter by one, but prevents the counter from going to zero
func (c *Counter) Dec() {
// prevent overflow
if !c.isZero() {
atomic.AddUint64(&c.counter, ^uint64(0))
}
}
// Cancel sets the finished flag, and sets counter to zero
func (c *Counter) Cancel() {
if !c.isFinished() {
atomic.StoreUint32(&c.finished, 1)
atomic.StoreUint64(&c.counter, 0)
}
}
// isFinished returns true if finished
func (c *Counter) isFinished() bool {
return atomic.LoadUint32(&c.finished) == uint32(1)
}
// isZero returns true if counter is zero
func (c *Counter) isZero() bool {
return atomic.LoadUint64(&c.counter) == uint64(0)
}
更新:通过使用-race标志运行下面的代码,我能够检测到我确实需要包含互斥锁。
var counter *Counter = &Counter{}
func main() {
wg := sync.WaitGroup{}
numberOfLoops := 10
wg.Add(numberOfLoops)
for i := 0; i < numberOfLoops; i++ {
go incrementor(&wg)
}
wg.Wait()
fmt.Println("Final Counter:", counter.counter)
}
func incrementor(wg *sync.WaitGroup) {
rand.Seed(time.Now().UnixNano())
for i := 0; i < 20; i++ {
counter.Inc()
time.Sleep(time.Duration(rand.Intn(3)) * time.Millisecond)
}
wg.Done()
counter.Cancel()
}
潇潇雨雨
Helenr
相关分类