<p>I am reading this blog from the canonical <a href="http://nathanleclaire.com/blog/2014/02/15/how-to-wait-for-all-goroutines-to-finish-executing-before-continuing/" rel="nofollow">example</a></p>
<pre><code> package main
import (
"fmt"
"sync"
"time"
)
func main() {
messages := make(chan int)
var wg sync.WaitGroup
// you can also add these one at
// a time if you need to
wg.Add(3)
go func() {
defer wg.Done()
time.Sleep(time.Second * 3)
messages <- 1
}()
go func() {
defer wg.Done()
time.Sleep(time.Second * 2)
messages <- 2
}()
go func() {
defer wg.Done()
time.Sleep(time.Second * 1)
messages <- 3
}()
go func() {
for i := range messages {
fmt.Println(i)
}
}()
wg.Wait()
}
</code></pre>
<p>I am having a bit trouble figuring where is the race condition coming in</p>
<p>Is it because <code>wg.Add()</code> only adds the first 3 <code>go func</code>? So the <code>wg.Wait</code> will possibly cause the main thread to close first before the 4th <code>go func</code> executed?</p>
<p>Or is it because of not closing the channel?</p>
<hr/>**评论:**<br/><br/>whizack: <pre><p>the race is that goroutine 4 (the one that reads messages) can not guarantee complete execution before wg.Wait() clears. It is very possible at runtime that goroutine 1 (with the 3s sleep) will not print. The solution would be to make 2 WaitGroup objects and run a 5th goroutine that waits on the existing WaitGroup, closes the messages chan, and calls Done() on the 2nd WaitGroup, while the consumer goroutine calls Done() on the existing WaitGroup after the loop.</p></pre>danredux: <pre><p>Another way to explain the race is to look at what happens depending on which goroutine gets scheduled after the wg is done.</p>
<p>If the printing goroutine (the one reading the channel) becomes active, then it will finish reading and printing the messages. If the main goroutine (the wg.Wait one) becomes active, then it will end the program.</p>
<p>The cause of race conditions is <em>always</em> different things happening depending on which goroutine gets scheduled next, so it's a good way to think about it.</p></pre>Yojihito: <pre><p>I thought ranging over a channel blocks?</p></pre>nathj07: <pre><p>I reckoned running the race detector over it to see what it says about race conditions. Scanning the code myself I'm not seeing it. Use the tools.</p></pre>zenberserk: <pre><blockquote>
<p>Is it because wg.Add() only adds the first 3 go func? So the wg.Wait will possibly cause the main thread to close first before the 4th go func executed?</p>
</blockquote>
<p>Not sure what the actual context is, but moving the wg.Done() parts to the 'consumer' goroutine fixes the case:</p>
<p><a href="https://play.golang.org/p/PvPtN_m9-5" rel="nofollow">https://play.golang.org/p/PvPtN_m9-5</a></p></pre>hansdr: <pre><p>Ah, so you're marking a thread as done after its message has been consumed by the final goroutine. That's a nice and simple solution for waiting until all child threads are done. </p></pre>tmornini: <pre><p>Not threads, go routines.</p>
<p>They are not the same thing.</p></pre>
这是一个分享于 的资源,其中的信息可能已经有所发展或是发生改变。
入群交流(和以上内容无关):加入Go大咖交流群,或添加微信:liuxiaoyan-s 备注:入群;或加QQ群:692541889
- 请尽量让自己的回复能够对别人有帮助
- 支持 Markdown 格式, **粗体**、~~删除线~~、
`单行代码`
- 支持 @ 本站用户;支持表情(输入 : 提示),见 Emoji cheat sheet
- 图片支持拖拽、截图粘贴等方式上传