> Unless I don't know about something, bool read/write is an atomic operation
> - isn't it?
It's not. Nothing is.
http://golang.org/ref/mem
> One routine is only reading a bool variable, while the other one is only
> writing - so what is the problem that it sees here?
> Is there any solution to avoid reports about such things, other than
> wrapping the bool write/read with a useless mutex?
Yep, you can use a http://golang.org/pkg/sync/#RWMutex
or you can use a channel.
http://play.golang.org/p/19jvP4RFDU
On Monday, June 16, 2014 9:28:57 AM UTC+2, Jesse McNelis wrote:> Unless I don't know about something, bool read/write is an atomic operation
> - isn't it?
It's not. Nothing is.
http://golang.org/ref/memPlease explain me how is it possible for a bool read/write to not be an atomic operation?On the low level: how any existing CPU in the world and read or write a bool value only partially?Just the idea of that is ridiculous.
On Monday, June 16, 2014 9:28:57 AM UTC+2, Jesse McNelis wrote:> Unless I don't know about something, bool read/write is an atomic operation
> - isn't it?
It's not. Nothing is.
http://golang.org/ref/memPlease explain me how is it possible for a bool read/write to not be an atomic operation?On the low level: how any existing CPU in the world and read or write a bool value only partially?Just the idea of that is ridiculous.
Please explain me how is it possible for a bool read/write to not be an atomic operation?On the low level: how any existing CPU in the world and read or write a bool value only partially?Just the idea of that is ridiculous.A bool can be changed in a CPU register but not be flushed to main RAM, where other thread might read it after the original write and find old data.Bool writes are atomic in the sense that they can't be left half-done, but they can't guarantee sequential consistency, which is needed to avoid data races in many cases.Kind regards,Jon Valdes
On Monday, June 16, 2014 9:56:56 AM UTC+2, Jon Valdés wrote:Please explain me how is it possible for a bool read/write to not be an atomic operation?On the low level: how any existing CPU in the world and read or write a bool value only partially?Just the idea of that is ridiculous.A bool can be changed in a CPU register but not be flushed to main RAM, where other thread might read it after the original write and find old data.Bool writes are atomic in the sense that they can't be left half-done, but they can't guarantee sequential consistency, which is needed to avoid data races in many cases.Kind regards,Jon ValdesOK - that makes sense, thank you for explaining.But then, don't you think that we should have atomic.StoreBool, atomic.StoreByte and atomic.StoreUint16 ?
It's just does not make much sense that there are no such functions, forcing users to wrap single byte writes around complex solutions involving mutexes or channels.
> Please explain me how is it possible for a bool read/write to not be an
> atomic operation?
> On the low level: how any existing CPU in the world and read or write a bool
> value only partially?
> Just the idea of that is ridiculous.
The size of a bool isn't defined in the language spec. It's size compared to the word size of any CPU is unknown.
But more importantly, If the two goroutines are running on threads on
different CPUs that don't share a cache then there is no reason for
one to ever see the mutations of the other without synchronisation.
If you can properly demonstrate the need for it, with overwhelming evidence, then it probably makes sense... otherwise not.
It's just does not make much sense that there are no such functions, forcing users to wrap single byte writes around complex solutions involving mutexes or channels.Tell the full story; what are you implementing that needs this?
If you can properly demonstrate the need for it, with overwhelming evidence, then it probably makes sense... otherwise not.Overwhelming evidence? That's a good one :)No sorry, I am not going to provide with an overwhelming evidence for the fact that applications where one routine is only there to read a bool value, while another one only writes to it are quite a common in the software development world.
It's just does not make much sense that there are no such functions, forcing users to wrap single byte writes around complex solutions involving mutexes or channels.Tell the full story; what are you implementing that needs this?I gave you a story with my example.There is a routine that I want to stop at some point and stopping is by setting a bool variable is the most optimal way to do it.
I don't know examples where such place would be performance critical...One trivial way to accomplish this:type Loop uint32 // wasn't able to think of a better namefunc (v *Loop) Done() bool { return atomic.LoadUint32(v) == 1 }func (v *Loop) Term() { atomic.StoreUint32(v, 1) }for !loop.Done() { ... }There's also Tomb package http://godoc.org/gopkg.in/tomb.v1 that does something similar.Depending on your problem there can be other solutions... which is why I'm asking for the specific problem you are having... not the abstract "stop something" problem.
On Mon, Jun 16, 2014 at 9:18 AM, Piotr Narewski <piot...@gmail.com> wrote:
> Race detector is a very nice and useful tool, but sometimes it really pisses
> me off.
>
> For example, I don't see any reason why it keeps reporting a data race on
> such a program:
> http://play.golang.org/p/yiAa7XQ74U
>
> Unless I don't know about something, bool read/write is an atomic operation
> - isn't it?
The race (it _is_ a race) is not relevant to (CPU specific) atomic
bool read/write, because according to the memory model the compiler is
free to never write any value whatsoever to the stop variable. The
compiler may keep the value in a register only or even discard the
statement in its entirety.
On Mon, Jun 16, 2014 at 7:34 PM, Jesse McNelis <jes...@jessta.id.au> wrote:
> I think that's a bug/missing feature in the race detector.
> An atomic.Store() without an atomic.Load() is a race.
yep, https://code.google.com/p/go/issues/detail?id=7621
--
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...@googlegroups.com.
For more options, visit https://groups.google.com/d/optout.
As has been mentioned, an atomic read/write can't be done to a variable smaller than a certain size. See http://stackoverflow.com/questions/14624776/can-a-bool-read-write-operation-be-not-atomic-on-x86. Use uint32 if you want to use sync/atomic, or go with one of the other methods. The most common one seems to be closing a channel to signal shutdown; this is nice because it plays well with other asynchronous events via the select statement.
>I read that, but I still cannot believe that you guys can do atomic additions to a 64 bit integer (even on a 32 bit platform), but you cannot do atomic read/write of a single byte.Last time I checked, this is "golang-nuts", not "x86-cpu-hardware-designers-nuts".
But now you are suggesting that inside mutex.Unlock() there is a special code that flushes all the "cached" data of global variables into the memory.
Except that there isn't - I checked it.
The mutex operations are solely about synchronization of routines and they don't do anything about runtime memory management.
Memory ordering and variables that live in registers vs living in memory cause multiple cpu shared memory to more subtle than you realize.You do realise C and Java have the volatile keyword for this reason (to ensure memory visibility across threads) and that Go does not have a volatile qualifier so cannot guarantee that every store causes a reload of the variable. Perhaps you think you are an expert on CPU's but perhaps not compilers.
--
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...@googlegroups.com.
For more options, visit https://groups.google.com/d/optout.
Gentlemen, you are debating a topic that you seem to know only from Wikipedia with a guy who has spent half of his life on programming multi-thread software in C.
On 17 Jun 2014 09:25, "Piotr Narewski" <piot...@gmail.com> wrote:
>
> Gentlemen, you are debating a topic that you seem to know only from Wikipedia with a guy who has spent half of his life on programming multi-thread software in C.
I'm flabbergasted. How can someone with such experience as yours have such utter lack of knowledge about how *modern* CPUs and compilers work? (As evidenced by all your posts to this thread)
It seems to me that your knowledge is based on empirical and anecdotal evidence not backed by actual facts. People have tried to explain to you why you are wrong multiple times on this thread, and you completely ignore them and continue stating your overly-simplistic view of how things work or how they should work.
I suggest reading the information you are given before lecturing people about *their* knowledge. Starting with this excellent article which was already posted on this thread which you don't seem to have read:
https://software.intel.com/en-us/blogs/2013/01/06/benign-data-races-what-could-possibly-go-wrong
Or a quote from Walter Bright: ``You have to give up on volatile. Nobody agrees on what it means. What does "don't optimize" mean? And that's not at all the same thing as "atomic".``
It seems to me that your knowledge is based on empirical and anecdotal evidence not backed by actual facts. People have tried to explain to you why you are wrong multiple times on this thread, and you completely ignore them and continue stating your overly-simplistic view of how things work or how they should work.
Gentlemen, you are debating a topic that you seem to know only from Wikipedia with a guy who has spent half of his life on programming multi-thread software in C.
Or a quote from Walter Bright: ``You have to give up on volatile. Nobody agrees on what it means. What does "don't optimize" mean? And that's not at all the same thing as "atomic".``To understand what "don't optimize" means, I would first need to learn about what a C compiler is.
First, the Standard’s constraints on (volatile) observable behavior are only for an abstract machine defined by the Standard, and that abstract machine has no notion of multiple threads of execution. As a result, though the Standard prevents compilers from reordering reads and writes to volatile data within a thread, it imposes no constraints at all on such reorderings across threads. At least that’s how most compiler implementers interpret things. As a result, in practice, many compilers may generate thread-unsafe code from the source above. If your multi-threaded code works properly with volatile and doesn’t work without, then either your C++ implementation carefully implemented volatile to work with threads (less likely), or you simply got lucky (more likely). Either case, your code is not portable.
That's exactly my point. I said that *you* do not provide actual facts. When you "proved" that here:
https://groups.google.com/d/msg/golang-nuts/dy4aImQAPvk/N2DEZQY3EQIJ
You provided empirical and anecdotal evidence, not facts. That might work for the majority of cases, but it will break in subtle ways under different circumstances.
On 17 June 2014 16:25, Piotr Narewski <piot...@gmail.com> wrote:
Gentlemen, you are debating a topic that you seem to know only from Wikipedia with a guy who has spent half of his life on programming multi-thread software in C.
I'd like to point out that some of the people commenting in this thread are world experts on compilers and multicore programming.
For a guy that has spent "half his life programming multi-thread software in C" you do seem to have some strange notions that seem incorrect to me.Since I started working on Go I have learned a lot about modern CPUs that surprised me. They are **very** different from the CPUs I grew up programming against. Maybe this is the case for you, too.If you want an atomic bool, just use atomic.(Load|Store)Int32. That's what I have done in the past. It's very fast and easy.
(Your aligns.go program "proves" nothing, by the way. It is possible to write all kinds of programs that behave correctly today—with the current compiler and the current language on your current system—but may be totally incorrect tomorrow. The advice you are receiving in this thread (and from the race detector!) is given to try to help you write robust code that will be always correct.)
The point of argument isn't about a bool storing atomically (it probably does), its about data visibility between threads. By the way, you haven't explained anything to me about what volatile means. You have reiterated what is a common misconception (which I previously held, about the C version of the volatile keyword.), proving you didn't read or understand anything posted AT ALL.
int a;void f() {
a=0;
a++;
}
As many people have now pointed out, even if we use a
machine instruction that operates on a single byte, that does not
guarantee that the value that you have now written is flushed to the
other copies of "a" that other goroutines might be reading.
I am not disagreeing with it and I really don't understand why you keep repeating the same thing over and over again.
On 17 June 2014 18:53, Piotr Narewski <piot...@gmail.com> wrote:I am not disagreeing with it and I really don't understand why you keep repeating the same thing over and over again.
Because you later said "...for me it is just a basic knowledge that one-byte store instruction is always atomic," and "...show me an example code where a bool write would not be atomic operation." With which you now apparently disagree.
On top of that you've been pretty rude and insulting. It is you who started questioning other people's experience and boasted of your own. If you have a sound argument then such claims are totally unnecessary. Please just stick to the pertinent facts next time, please.
I am not disagreeing with it
On Tuesday, June 17, 2014 10:02:20 AM UTC+2, andrewc...@gmail.com wrote:The point of argument isn't about a bool storing atomically (it probably does), its about data visibility between threads. By the way, you haven't explained anything to me about what volatile means. You have reiterated what is a common misconception (which I previously held, about the C version of the volatile keyword.), proving you didn't read or understand anything posted AT ALL.I thought I already did explain you what volatile means in C.It mans that C compiler does not optimize access to/form the certain variable; whenever there is a reference to a volatile variable in the code, you have it guaranteed that it happens exactly in the place where you wanted.Sorry, I just cannot phase it any simpler.Though, I can give you an example - maybe that will stimulate your imagination.You obviously like studying blog articles, so let me write a short one for you. :)Let's say we have a code like this:int a;void f() {a=0;a++;a+=2;}The above code will likely cause a compiler to just store 3 in a. But if you declare a as volatile, then it will first store 0 there, then it will increase it by 1, and then by another 2 - you don't even have it guaranteed to be 3 at the end, since another thread may modify the value in between and before each addition a gets re-fetched from memory. Because the access to a is not optimized, after you defined it as volatile.
I am not disagreeing with itWhich means topic is done and you can finally correctly rewrite your original loop asselect {case <-quit:default:}without discussing operations atomicity
Give me a break :)Half of the people in this topic have been pretty rude and insulting to me and it definitely wasn't me who started.In fact I've been pretty lenient and tolerant, considering how hostile you guys had been towards me.
It's just does not make much sense that there are no such functions, forcing users to wrap single byte writes around complex solutions involving mutexes or channels.