On Tue, Apr 14, 2020 at 4:39 AM Slawomir Pryczek <slawek1...@gmail.com> wrote:
>
> Hi Guys, was wondering about some things related to multithread code.
>
> 1. If data that is accessed or changed - it needs to go into CPU cache first, 
> and AFAIK to caches whole memory block not just this single area of memory on 
> which we're operating. When we're doing writes without synchronization to 
> something which is tightly packed, how does it work that cache isn't 
> poisoned, and the result is still correct, even if each cpu core is having 
> its own L1 and L2 caches?

If you use atomic writes, the CPU cores will communicate to either
invalidate cache lines or provide an update of the new memory
contents.  On x86 this happens even if you don't do an atomic write.
On some other processors, the other CPU cores can see old data in that
memory address for some period of time.


> Are such patterns, when single thread is only operating on single cell(s) of 
> memory, considered thread safe for slices and in general?
> https://play.golang.org/p/rF8jPEGDZzk

As far as I know this is safe on all modern multi-core processors.
They will use cache snooping or other techniques to make sure that at
most one core has a dirty version of a particular cache line.  Of
course, if there are many cores the performance can be quite bad.


> 2. For lazy initialization double-check pattern. I found on several sources 
> that it is safe, still race detector complains about data races (which is 
> correct because there is race, which is done on purpose) - 
> https://software.intel.com/en-us/node/506123
> And of course this code seems to be working as expected
>
> https://play.golang.org/p/gUzWHr-1K9H

This is unsafe in general because nothing ensures that memory changes
made before setting initialized to true are visible to other cores
that happen to see initialized set to true.  That is, in your example,
some other core could see the variable initialized set to true without
seeing any values stored in the variable myconfig.  That can't happen
on x86, which enforces memory ordering of writes, but it can happen on
other non-x86 processors.

Note that I think that your link to software.intel.com doesn't support
your argument even on x86, as in that link they are using atomic
writes, but your code is using ordinary writes.


> 3. Now question is, can i disable these warnings somehow so race detector 
> won't complain about safe code because i have ton of these and it's 
> obfuscating usable output?

No.  Your code isn't safe, and the race detector should and will complain.


> 4. Im not sure about instruction ordering, will it always be the case that 
> threads that see initialized=true will also see myconfig AFTER the update, 
> because myconfig isn't synchronized. Would it be better to just use pointer 
> instead and check for nil value or even atomic.Value?

It would be better to use a sync.Mutex or, if absolutely necessary,
use the calls in the sync/atomic package.


> 5. How these patterns are working with other CPUs, are they considered unsafe 
> on anything other than intel architecture?

As noted Intel architectures enforce a global write ordering.  That is
not true on most other multi-core processors.


> So im writing some code which will do hundreds of thousands of operations per 
> second and these operations need to read config (probably in some cases at 
> multiple places). You think using just atomic.Value (Store/Load) will have 
> impact when i run it on machine with eg. 96 cores? Maybe RW mutex would be 
> better? What you think? I could just run some synthetic benchmarks but for 
> these usually seem to not have much use in real life scenarios for 
> multithreaded code.

I agree that synthetic benchmarks are unlikely to help.  You'll have
to benchmark your real code.

There is no single answer as to what is best as it depends on things
like the number of reads compared to the number of writes, and what
happens if you use out of date data, and what is driving your
operations.  For example, in Go, if your operations are being driven
by channel data, and if it doesn't matter if you use slightly out of
date configuration information, then it's easy enough to send
configuration updates on a channel and have the workers use select to
pick up either the next data item or the configuration change.  I
don't know whether that makes any sense for your situation.

Ian

-- 
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 on the web visit 
https://groups.google.com/d/msgid/golang-nuts/CAOyqgcUmptjAYSqCa5OP5%2B5xmhEw6mzYgu7PX%3D1ouGbp-Sttyw%40mail.gmail.com.

Reply via email to