英文:
Simulating waitgroups using Go atomics
问题
我有以下代码来生成一些Goroutine。每个Goroutine执行不同数量的工作(在这里通过不同的循环长度模拟),然后原子地设置其作业结构中的变量以表示完成。主Goroutine使用compare_and_swap检查所有作业结构是否完成。这段代码存在竞争条件,变量finish
超过了numjobs
,我不明白为什么会这样。
我知道可以使用waitgroups来实现这一点,但是我想了解为什么这种方法失败了。
type job struct {
id int
done uint32
loops int
}
const (
numjobs int = 10000
)
func (j *job) work() {
for k := 0; k < j.loops; k++ {
}
fmt.Printf("Ending job %d\n", j.id)
atomic.StoreUint32(&j.done, 1)
}
func main() {
// Memory for jobs
jobs := make([]job, numjobs)
// Kick off the jobs, each running a random number of loops
for i := 0; i < numjobs; i++ {
jobs[i].id = i
jobs[i].loops = rand.Intn(1000000)
go (&jobs[i]).work()
}
// Track when all jobs are done
finish := 0
for finish != numjobs {
for _, job := range jobs {
if atomic.CompareAndSwapUint32(&job.done, 1, 0) {
finish++
}
}
fmt.Printf("Finished %d jobs\n", finish)
}
}
英文:
I have the following code to spawn a number of Goroutines. Each Goroutine does a variable amount of work (simulated here by different loop lengths) and then atomically sets a variable in its job structure to signal its done. The main() Goroutine checks all the job structures for completion using compare_and_swap. This code is racy, the variable finish
goes beyond numjobs
, and I don't understand why.
I know I can use waitgroups to achieve this, however, I want to understand why this fails.
type job struct {
id int
done uint32
loops int
}
const (
numjobs int = 10000
)
func (j *job) work() {
for k := 0; k < j.loops; k++ {
}
fmt.Printf("Ending job %d\n", j.id)
atomic.StoreUint32(&j.done, 1)
}
func main() {
// Memory for jobs
jobs := make([]job, numjobs)
// Kick off the jobs, each running a random number of loops
for i := 0; i < numjobs; i++ {
jobs[i].id = i
jobs[i].loops = rand.Intn(1000000)
go (&jobs[i]).work()
}
// Track when all jobs are done
finish := 0
for finish != numjobs {
for _, job := range jobs {
if atomic.CompareAndSwapUint32(&job.done, 1, 0) {
finish++
}
}
fmt.Printf("Finished %d jobs\n", finish)
}
}
答案1
得分: 2
你正在更新 job
的副本。尝试这样做:
for job := range jobs {
if atomic.CompareAndSwapUint32(&jobs[job].done, 1, 0) {
finish++
}
}
英文:
You are updating a copy of the job
. Try this:
for job := range jobs {
if atomic.CompareAndSwapUint32(&jobs[job].done, 1, 0) {
finish++
}
}
通过集体智慧和协作来改善编程学习和解决问题的方式。致力于成为全球开发者共同参与的知识库,让每个人都能够通过互相帮助和分享经验来进步。
评论