Why is this working on my machine?
Link: https://play.golang.org/p/K8ndH7DUzq (result: proccess too long)
In my machine: Done hello, world
评论:
peterbourgon:
aristofanio: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.
aristofanio:I think that at some point should give the same result of the playground. Or no?
dchapes:That I understand. What I did not understand was the different behavior always.
nhooyr:That I understand
Not trying to be rude, but I don't think you do. The behaviour of a program containing a race is undefined. 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.
xiaonanln:No idea why people down voted you... This sub is unbelievable sometimes..
aristofanio: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.
Kraigius:Thanks! I think that you are correct, but I not found anything document on this.
aristofanio:Imo, I don't see why they should document any steps they take to prevent denial of service.
An infinite loop would obviously be unwanted on that kind of service.
aristofanio:And this? Why not work?
aristofanio:Excuse me. (My) Conceptual error. I understand now. Thank you all.
Kraigius:Best lesson: https://play.golang.org/p/WfWkzd60qR
:Are you asking for explanation?
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.
lausan:[deleted]
:I wouldn't consider a program with undefined behavior correct...
lausan:[deleted]
dchapes: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 go memory model article is a good read
iroflmaowtf:because your "done" is a boolean, either true or false
Are you claiming that having a race on a boolean variable is okay? That, for example, having one go routine do
for !done { /something/ }
and another dodone = true
is okay??If not, please clarify what you do mean.
If so, you are very very wrong. Please read Benign data races: what could possibly go wrong?.
which part is undefined again?
The entire behaviour of a program from the moment it encounters a race.
In your example:
func setup() { a = "hello, world" done = true }
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
done
to true (whichmain
sees and accesses either uninitialised or garbagea
value) and then latersetup
writes toa
. The linked article above gives other less obvious (and less likely for such simple examples) possibilities.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.
dchapes:you do understand that you can either read either
true
orfalse
and not a third state, at any point, right?!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.
iroflmaowtf:you do understand that you can either read either true or false and not a third state, at any point, right?
You have an all too common misconception of why races are bad. Please read the above linked to article.
You do understand that the compiler is free to re-order code, right?
You do understand a valid and correct implementation of a Go compiler is allowed to take:
a = "hello, world" done = true
and generate code equivalent to:
done = true runtime.Gosched() a = "hello, world"
or (as an extreme example) to generate code equivalent to:
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"
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.
I've read the linked article...
done
is global, the compiler would be pretty silly to reuse the value ofdone
for anything, wouldn't you think so?and your example with
tmp
, while I understand what you mean, isn't a clear indication of why the compiler would usedone
to temporarily hold the value oftmp
, but ok.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
no sane compiler, under any circumstance, should repurpose a global variable
