<p>Why is this working on my machine?</p>
<p>Link: <a href="https://play.golang.org/p/K8ndH7DUzq" rel="nofollow">https://play.golang.org/p/K8ndH7DUzq</a> (result: proccess too long)</p>
<p>In my machine: Done hello, world</p>
<hr/>**评论:**<br/><br/>peterbourgon: <pre><p>You have a data race, and so the program has undefined behavior. Specifically, you can't both read and write the done variable from multiple goroutines without some form of synchronization. </p></pre>aristofanio: <pre><p>I think that at some point should give the same result of the playground. Or no?</p></pre>aristofanio: <pre><p>That I understand. What I did not understand was the different behavior always.</p></pre>dchapes: <pre><blockquote>
<p>That I understand</p>
</blockquote>
<p>Not trying to be rude, but I don't think you do. <a href="https://software.intel.com/en-us/blogs/2013/01/06/benign-data-races-what-could-possibly-go-wrong" rel="nofollow">The behaviour of a program containing a race is <strong>undefined</strong>.</a> That means different compiler implementations, different architectures, and even different runs on the same hardware without changing anything are allowed to do whatever and the behaviour can change each time.</p></pre>nhooyr: <pre><p>No idea why people down voted you... This sub is unbelievable sometimes..</p></pre>xiaonanln: <pre><p>I think it's because play.golang.org wouldn't let your code run for that long time. go setup() will create a new goroutine but it's not executed immediately. The for loop takes 100% CPU, maybe play.golang.org detects this abnormal behavior and just shut your code down.</p></pre>aristofanio: <pre><p>Thanks! I think that you are correct, but I not found anything document on this.</p></pre>Kraigius: <pre><p>Imo, I don't see why they should document any steps they take to prevent denial of service.</p>
<p>An infinite loop would obviously be unwanted on that kind of service.</p></pre>aristofanio: <pre><p>And this? Why not work?</p>
<p>Link: <a href="https://play.golang.org/p/kZwGEY1Nz4" rel="nofollow">https://play.golang.org/p/kZwGEY1Nz4</a></p></pre>aristofanio: <pre><p>Excuse me. (My) Conceptual error. I understand now. Thank you all.</p>
<p>Link: <a href="https://play.golang.org/p/R5a2u7Xxc2" rel="nofollow">https://play.golang.org/p/R5a2u7Xxc2</a></p></pre>aristofanio: <pre><p>Best lesson:
<a href="https://play.golang.org/p/WfWkzd60qR" rel="nofollow">https://play.golang.org/p/WfWkzd60qR</a></p></pre>Kraigius: <pre><p>Are you asking for explanation?</p>
<p>Line 21 is waiting for the lock before continuing with the execution of G(). However, it will never get the lock as G() itself needs to complete before F() will unlock the mutex.</p></pre>: <pre><p>[deleted]</p></pre>lausan: <pre><p>I wouldn't consider a program with undefined behavior correct...</p></pre>: <pre><p>[deleted]</p></pre>lausan: <pre><p>Pretty much the whole program. You have no guarantees about what it will do and any behavior you happen to see from it now could change at any point since it's undefined. In addition to the data race article I think the <a href="https://golang.org/ref/mem" rel="nofollow">go memory model</a> article is a good read</p></pre>dchapes: <pre><blockquote>
<p>because your "done" is a boolean, either true or false</p>
</blockquote>
<p>Are you claiming that having a race on a boolean variable is okay? That, for example, having one go routine do <code>for !done { /*something*/ }</code> and another do <code>done = true</code> is okay??</p>
<p>If not, please clarify what you do mean.</p>
<p>If so, you are very very wrong. Please read <a href="https://software.intel.com/en-us/blogs/2013/01/06/benign-data-races-what-could-possibly-go-wrong" rel="nofollow">Benign data races: what could possibly go wrong?</a>.</p>
<blockquote>
<p>which part is undefined again?</p>
</blockquote>
<p>The entire behaviour of a program from the moment it encounters a race.</p>
<p>In your example:</p>
<pre><code>func setup() {
a = "hello, world"
done = true
}
</code></pre>
<p>The compiler is free to re-order these lines or stick any junk it wants into those variables as long as by the time the function exits it has written the values given to the variables. The most obvious possible outcome of this is that a valid Go compiler could first set <code>done</code> to true (which <code>main</code> sees and accesses either uninitialised or garbage <code>a</code> value) and then later <code>setup</code> writes to <code>a</code>. The linked article above gives other less obvious (and less likely for such simple examples) possibilities.</p>
<p>To be perfectly clear, the code you linked to is wrong, it is not a valid Go program according to the Go language specification and memory model. Because it happens to not get rejected by the compiler and because it happens to produce desired output with a specific version of a specific implementation of a specific Go compiler is completely irrelevant. </p></pre>iroflmaowtf: <pre><p>you do understand that you can either read either <code>true</code> or <code>false</code> and not a third state, at any point, right?!</p>
<p>a mutex(or other sync mech) is needed when the data can be read partially, example: an int64 while your program is a 32bit one, when multiple variables are needed to be "in sync", etc.</p></pre>dchapes: <pre><blockquote>
<p>you do understand that you can either read either true or false and not a third state, at any point, right?</p>
</blockquote>
<p>You have an all too common misconception of why races are bad. <em>Please</em> read the above linked to article.</p>
<p>You do understand that the compiler is free to re-order code, right?</p>
<p>You do understand a valid and correct implementation of a Go compiler is allowed to take:</p>
<pre><code>a = "hello, world"
done = true
</code></pre>
<p>and generate code equivalent to:</p>
<pre><code>done = true
runtime.Gosched()
a = "hello, world"
</code></pre>
<p>or (as an extreme example) to generate code equivalent to:</p>
<pre><code>a = "some random junk, see previous linked article about when/why it might want to do so"
var tmp int8 = 42
*((*int8)(unsafe.Pointer(&done))) = tmp
runtime.Gosched()
done = true
runtime.Gosched()
a = "hello, world"
</code></pre>
<p>The above code is convoluted but, again, a perfectly valid thing for a correct Go compiler to do as it will not change the behaviour of any valid Go program.</p></pre>iroflmaowtf: <pre><p>I've read the linked article...</p>
<p><code>done</code> is global, the compiler would be pretty silly to reuse the value of <code>done</code> for anything, <strong><em>wouldn't you think so</em></strong>?</p>
<p>and your example with <code>tmp</code>, <em>while I understand what you mean</em>, isn't a clear indication of why the compiler would use <code>done</code> to temporarily hold the value of <code>tmp</code>, but ok.</p>
<p>now, if you had a function, with 3 variables, and the compiler could "free" one of them by "reusing" one, it may freely do so, because there's no side-effect induced</p>
<p>no sane compiler, under any circumstance, should repurpose a global variable</p></pre>
这是一个分享于 的资源,其中的信息可能已经有所发展或是发生改变。
入群交流(和以上内容无关):加入Go大咖交流群,或添加微信:liuxiaoyan-s 备注:入群;或加QQ群:692541889
- 请尽量让自己的回复能够对别人有帮助
- 支持 Markdown 格式, **粗体**、~~删除线~~、
`单行代码`
- 支持 @ 本站用户;支持表情(输入 : 提示),见 Emoji cheat sheet
- 图片支持拖拽、截图粘贴等方式上传