关于sync.WaitGroup中wg.Add()放置位置的技术疑问
wg.Add(1) outside the goroutine ensure v equals 100? Great question—let’s break this down step by step to make everything clear.
First, let’s recap why your first code snippet fails:
The
wg.Add(1)is placed inside the anonymous goroutine. When you launch 100 goroutines withgo func(), there’s no guarantee when each goroutine will start executing. The main goroutine might hitwg.Wait()before some (or even many) of the goroutines have runwg.Add(1). SinceWait()unblocks when the wait group counter reaches 0, if the main goroutine gets there before enoughAdd(1)calls happen, it exits early, leaving some goroutines uncounted. Theiratomic.AddInt32calls might never finish before the program exits, which is whyvis always less than 100.
Now let’s look at the fixed version where wg.Add(1) lives inside the loop before launching the goroutine (note: I added the missing parentheses () after the anonymous function—you need those to actually execute the function):
var wg sync.WaitGroup var v int32 = 0 for i = 0; i < 100; i++{ wg.Add(1) // Correct: increment counter BEFORE starting the goroutine go func(){ atomic.AddInt32(&v,1) wg.Done() }() } wg.Wait() fmt.Println(v)
Why this guarantees v equals 100
The critical detail here is that wg.Add(1) runs synchronously in the main goroutine, before we ever launch the corresponding goroutine.
Let’s walk through the flow:
- For each loop iteration, the main goroutine first increments the wait group counter by 1. This means the counter is guaranteed to account for the goroutine before the goroutine is even scheduled to run.
- We then launch the goroutine. Even if the goroutine takes time to start executing, the wait group already knows it exists.
- By the time the main goroutine reaches
wg.Wait(), the wait group counter is already at 100 (we ranwg.Add(1)100 times in the loop). The main goroutine will block untilwg.Done()is called exactly 100 times—once for each goroutine. - Each goroutine safely increments
vwithatomic.AddInt32(which handles concurrent access without race conditions) and then callswg.Done()to decrement the counter. Once all 100 are done, the counter hits 0,wg.Wait()unblocks, and we printvwhich is now exactly 100.
Could the main goroutine unblock early?
No, that’s impossible in this setup. Here’s why:
- The
forloop runs entirely synchronously in the main goroutine. We don’t launch any goroutines until after we’ve incremented the wait group counter for that iteration. - The main goroutine can’t reach
wg.Wait()until it finishes all 100 loop iterations—and thus all 100wg.Add(1)calls. By the time we get toWait(), the counter is already at 100, soWait()will only unblock after all 100Done()calls are made.
内容的提问来源于stack exchange,提问作者user13505500




