Home > Software design >  Simulating waitgroups using Go atomics
Simulating waitgroups using Go atomics

Time:08-19

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

}

CodePudding user response:

You are updating a copy of the job. Try this:

       for job := range jobs {
            if atomic.CompareAndSwapUint32(&jobs[job].done, 1, 0) {
                finish  
            }
        }
  • Related