英文:
how to implement atomic add but not exceed x?
问题
我想要在纯原子操作中实现以下的add
函数:
var num int
func add(max int) int {
if num < max {
num++
}
return num
}
我尝试了一个版本:
func add(max int64) int64 {
for {
old := atomic.LoadInt64(&x)
if old + 1 < max {
if atomic.CompareAndSwapInt64(&x, old, old+1) {
return old+1
}
} else {
return old
}
}
}
然而,我猜想可能有一种更好的解决方案,可以减少失败的机会并避免死循环。
英文:
i want to implement add
below in pure atomic operation
var num int
func add(max int) int {
if num < max {
num++
}
return num
}
i have try one edition
func add(max int64) int64 {
for {
old := atomic.LoadInt64(&x)
if old + 1 < max {
if atomic.CompareAndSwapInt64(&x, old, old+1) {
return old+1
}
} else {
return old
}
}
}
however, i guess there might be a better solution with less fail chance and avoid dead loop
答案1
得分: 1
这是您的算法的修订版本,其中包含了多个goroutine的测试。它通过了带有和不带有Go竞争检测器的测试。
add.go
:
package main
import (
"fmt"
"runtime"
"sync"
"sync/atomic"
)
var x int64 = -42
func add(max int64) int64 {
for {
old := atomic.LoadInt64(&x)
if old >= max {
return old
}
new := old + 1
if atomic.CompareAndSwapInt64(&x, old, new) {
return new
}
}
}
func main() {
const max = 123456
fmt.Println("max:", max)
fmt.Println("x: ", x)
var wg sync.WaitGroup
procs := runtime.GOMAXPROCS(0)
for i := 0; i < procs; i++ {
wg.Add(1)
go func(max int64) {
defer wg.Done()
for {
if add(max) >= max {
return
}
}
}(max)
}
wg.Wait()
fmt.Println("x: ", x)
}
https://go.dev/play/p/r-qsnyI7tqv
$ go build -race add.go && ./add
max: 123456
x: -42
x: 123456
$ go build add.go && ./add
max: 123456
x: -42
x: 123456
英文:
Here's a revised version of your algorithm with a multiple goroutine test. It passes the test with and without the Go race detector.
add.go
:
package main
import (
"fmt"
"runtime"
"sync"
"sync/atomic"
)
var x int64 = -42
func add(max int64) int64 {
for {
old := atomic.LoadInt64(&x)
if old >= max {
return old
}
new := old + 1
if atomic.CompareAndSwapInt64(&x, old, new) {
return new
}
}
}
func main() {
const max = 123456
fmt.Println("max:", max)
fmt.Println("x: ", x)
var wg sync.WaitGroup
procs := runtime.GOMAXPROCS(0)
for i := 0; i < procs; i++ {
wg.Add(1)
go func(max int64) {
defer wg.Done()
for {
if add(max) >= max {
return
}
}
}(max)
}
wg.Wait()
fmt.Println("x: ", x)
}
https://go.dev/play/p/r-qsnyI7tqv
$ go build -race add.go && ./add
max: 123456
x: -42
x: 123456
$ go build add.go && ./add
max: 123456
x: -42
x: 123456
答案2
得分: 0
最简单(但不是最高效)的解决方案是使用互斥锁:
var (
mu sync.Mutex
num int64
)
func add(max int64) int64 {
mu.Lock()
defer mu.Unlock()
if num < max {
num++
}
return num
}
请注意,这段代码使用了互斥锁(sync.Mutex
)来确保在修改 num
变量时的线程安全性。mu.Lock()
用于获取锁,mu.Unlock()
用于释放锁。在 add
函数中,我们首先获取锁,然后在修改 num
变量之前检查其值是否小于 max
。如果是,则将 num
递增。最后,我们释放锁并返回 num
的值。
英文:
The easiest (but not the most efficient) solution would be to use a mutex:
var (
mu sync.Mutex
num int64
)
func add(max int64) int64 {
mu.Lock()
defer mu.Unlock()
if num < max {
num++
}
return num
}
通过集体智慧和协作来改善编程学习和解决问题的方式。致力于成为全球开发者共同参与的知识库,让每个人都能够通过互相帮助和分享经验来进步。
评论