I think I got a little overzealous with my opinions, it wasn't my intent to
be particularly prescriptive. I also did not get the impression that you
were suggesting the memory model should be different.

Bottom line: yes, it's possible to implement but more fragile in Go due to
the less-thoroughly-specified memory model. (I think we're in agreement
there.)

(Minor point, but I do think making the shared variables atomic is good
enough for some cases (like perhaps the overly-simplified Point example).
If you've got *only* reads, even atomic loads should still keep everything
in a shared state across all caches, so no flushing. Especially true on
amd64 with TSO where atomic loads compile down to exactly the same
instruction, just with less reordering allowed at the compiler level.
Writes are of course more expensive for both the reader and writer. Though
yeah, if the shared state is big enough, I'd probably take a different
approach altogether, same as you suggest.)

RE: the race detector, I can get https://go.dev/play/p/UuIWVlV0UTN to trip
the race detector if:
1. I remove the Println calls.
2. I remove the Sleep call.

(The copy of `data` that's read by each reader goroutine is written to some
independent global variable by each reader goroutine to satisfy the
compiler.)

I suspect what's happening is that the locking inside Println combined with
the relatively low frequency of writes is making it so that the race
detector does not actually ever observe a racy read/write. It's also a
single int that's being loaded and stored, so the race window is quite
small.

On Fri, Jan 31, 2025 at 1:12 PM robert engels <reng...@ix.netcom.com> wrote:

> To clarify, my op was to understand if this could be done in Go, which
> Bruno showed it can, and know I’d like to know why the race detector is not
> complaining…
>
> I wasn’t making any attempt at creating a more specified Go memory model.
> It is what it is.
>
> On Jan 31, 2025, at 12:09 PM, robert engels <reng...@ix.netcom.com> wrote:
>
> Yes, Java has a very detailed and explicit memory model which makes things
> like this doable.
>
> Although the ideas you propose are workable, the primary purpose of this
> is performance based - otherwise you would simply use a mutex. The problem
> with making every shared variable an atomic is that you pay the
> atomic/fence cost on every access - read and write. Whereas in the Java
> case, there is no flushing of the cache at all if there has been no writer
> activity, and even if there is, it is a single cache flush per “bulk
> update”.
>
> There reason StampedLock is provided rather than modifying Point is DRY.
> If you need a highly concurrent shared data system (i know, don’t share
> data in Go…) which is often the case for HPC/HFT systems, StampedLock can
> be useful.
>
> Using channels and locks is simply too slow - see
> github.com/robaho/go-concurrency-test (old, but I think still applicable).
>
> I think a more viable performant replacement in Go is to use copy on write
> with an atomic object reference - which in most cases is going to be more
> performant than using a StampedLock.
>
> On Jan 31, 2025, at 11:55 AM, 'Michael Knyszek' via golang-nuts <
> golang-nuts@googlegroups.com> wrote:
>
> This is a well-known pattern (use an atomic counter to check if anyone
> else modified some data in a critical section and retry or fall back if it
> happened), but as the extensive Java docs imply, any such abstraction is
> going be fairly leaky. Java has a very thoroughly defined memory model that
> I suspect comes into play here to make the abstraction more usable (but
> don't quote me on that).
>
> You *could* do a very close read of the Go memory model and try to do
> something similar but you end up pushing a lot of these subtleties onto the
> caller. This would also require //go:norace annotations on the caller to
> not fail in the race detector. Neither I nor the memory model docs
> recommend this.
>
> The pattern is still useful and possible to apply in Go, however I have
> two suggestions:
> 1. Take the abstraction one level higher. Using the Java doc's Point
> example, what I mean is to only provide Point, not StampedLock. It's not
> too hard to implement a bespoke version of this sort of thing when you need
> it, and I find that doing these sorts of tricks benefits from breaking down
> the abstraction internally anyway, since it gives you more flexibility when
> adding new features.
> 2. Read and write the optimistically-read variables using the sync/atomic
> package. In the Point example from the Java docs, the optimistic read path
> would load x and y atomically (i.e. two separate Loads) and any write paths
> would store x and y atomically (i.e. two separate Stores). That's going to
> be far easier to reason about and more portable, though it might not
> achieve maximum performance on your hardware. If you're doing mostly
> optimistic reads (which I suspect is really when you'd want to consider
> this anyway), the optimistic reads themselves should scale just as well and
> you won't need to apply any //go:norace annotations. This suggestion is in
> the same vein as the "don't be clever" part of the memory model
> documentation.
>
> On Friday, January 31, 2025 at 6:14:24 AM UTC-5 Robert Engels wrote:
>
>> Hi,
>>
>> Do you think it is possible to implement a stamped lock in Go
>> https://docs.oracle.com/javase/8/docs/api/java/util/concurrent/locks/StampedLock.html
>>  ?
>>
>> It would seem that the Go race detector would always report the
>> “optimistic read” mode as a data race?
>>
>> (The docs state for Java that the values can be wildly inconsistent when
>> the optimistic read fails).
>>
>> Ideas on how to implement in Go?
>>
>
> --
> You received this message because you are subscribed to the Google Groups
> "golang-nuts" group.
> To unsubscribe from this group and stop receiving emails from it, send an
> email to golang-nuts+unsubscr...@googlegroups.com.
> To view this discussion visit
> https://groups.google.com/d/msgid/golang-nuts/10e6c142-fbdb-4c8d-8270-a836ab4cecf8n%40googlegroups.com
> <https://groups.google.com/d/msgid/golang-nuts/10e6c142-fbdb-4c8d-8270-a836ab4cecf8n%40googlegroups.com?utm_medium=email&utm_source=footer>
> .
>
>
>
>

-- 
You received this message because you are subscribed to the Google Groups 
"golang-nuts" group.
To unsubscribe from this group and stop receiving emails from it, send an email 
to golang-nuts+unsubscr...@googlegroups.com.
To view this discussion visit 
https://groups.google.com/d/msgid/golang-nuts/CAFza%2Bu-K6bPUCLiLM5zS6Uo6Phwu1UmCEz_NW_LsYhQ1gX_ATw%40mail.gmail.com.

Reply via email to