Live data from Hacker News

Data Race Patterns in Go

eng.uber.com

201–205 of 205 posts

Re: Data Race Patterns in Go

#201
post #143

Earlier quoted context omitted.

> so the signed integer you're using to count stuff up from zero might be -16 now, which is astonishing Actually, if it is an int, it is guaranteed to not be any number not explicitly set to (java has no-out-of-thin-air guarantees for 32-bit primitives). In practice on every modern implementation it is true of 64-bit primitives as well. So the prototypical data race condition of incrementing a primitive counter from…

Ooh, I did not know this. Do you happen to know where the "no-out-of-thin-air" guarantee is for the 32-bit primitives? Presumably in the Memory model docs somewhere?

I quickly glanced at the spec, but didn’t find it. But I didn’t make it up though, I remember reading it on the jvm mailing list and I found it here described by Brian Goetz himself: https://openjdk.org/projects/valhalla/design-notes/state-of-...

Re: Data Race Patterns in Go

#202
post #201

Earlier quoted context omitted.

Ooh, I did not know this. Do you happen to know where the "no-out-of-thin-air" guarantee is for the 32-bit primitives? Presumably in the Memory model docs somewhere?

I quickly glanced at the spec, but didn’t find it. But I didn’t make it up though, I remember reading it on the jvm mailing list and I found it here described by Brian Goetz himself: https://openjdk.org/projects/valhalla/design-notes/state-of-...

Thanks for that, it makes sense but it's good to know somebody specifically thought about this rather than "Eh, it seems to work".

Re: Data Race Patterns in Go

#203

Earlier quoted context omitted.

That's why I opened with "Look at the implementation". Go is unable to store the type and the pointer at the same time, so it warps what "atomic" means. Pretty much every other language has atomic mean "one of these will win, one will lose". Go says "one will win, one will panic and destroy the goroutine. In fact, it's even worse than that. If the Store() caller goes to sleep between setting the type and storing the…

> If the Store() caller goes to sleep between setting the type and storing the pointer, it causes every Goroutine that calls Load() to block. Where does this go to sleep: https://cs.opensource.google/go/go/+/refs/tags/go1.18.3:src/... It looks like a CAS busy loop with preemption disabled, to me.

Make sure to read between the lines. It only looks like a busy loop. Remember, the OS can pause and preempt your thread at any time. This is a real and likely event.

Re: Data Race Patterns in Go

#204
post #142

Earlier quoted context omitted.

That’s certainly how I interpreted it. It never occurred to me to think it meant “thread handles” specifically.

I meant it more in that "first-class" tends to mean "this is a thing that is represented in the language / type system". Go has first-class functions, because you can make a `var fn func() string` field/variable/argument/etc that holds a reference to a func that returns a string. Go does not have first-class types, because you can't reference or store a type directly. You can use reflection to pass a reflected thing…

I would say the notion of something being first-class is that you can manipulate it in the same way as a regular value in the language; in particular, you can use an expression that evaluates to such a thing in all the same ways that you can use a built-in version of that thing. Certainly Java does not have first-class types: you can pass a value that is sort of a representation a flattened form of a type, but you can't use that kind of value in a "new" expression or as a function return type.

AIUI Rust's async/await still has quite a lot of special case support. IMO concurrency is only really first-class in languages like Haskell where you can manipulate async actions the same way as a user-defined type and implement concurrency-related operations in plain old code.

Re: Data Race Patterns in Go

#205

Earlier quoted context omitted.

> If the Store() caller goes to sleep between setting the type and storing the pointer, it causes every Goroutine that calls Load() to block. Where does this go to sleep: https://cs.opensource.google/go/go/+/refs/tags/go1.18.3:src/... It looks like a CAS busy loop with preemption disabled, to me.

Make sure to read between the lines. It only looks like a busy loop. Remember, the OS can pause and preempt your thread at any time. This is a real and likely event.

By reading the lines and not between them, you could read these two lines: runtime_procPin() and runtime_procUnpin(). With explicit comments that these pause preemption.
Post reply on HN