From: Joshua Maurice on 20 Mar 2010 22:15 On Mar 21, 1:09 am, Andy Venikov <swojchelo...(a)gmail.com> wrote: > Joshua Maurice wrote: > >Leigh Johnston wrote: > >> Obviously the volatile keyword may not cause a memory barrier instruction to > >> be emitted but this is a side issue. The combination of a memory barrier > >> and volatile makes multi-threaded code work. > > > No. Memory barriers when properly used (without the volatile keyword) > > are sufficient. > > Sorry Joshua, but I think it's a wrong, or at least an incomplete, > statement. > > It all depends on how memory barriers/fences are implemented. In the > same way that C++ standard doesn't talk about threads it doesn't talk > about memory fences. If a memfence call is implemented as a library > call, then yes, you will in essence get a compiler-level fence directive > as none of the compilers I know of are allowed to move the code across a > call to a library. But oftentimes memfences are implemented as macros > that expand to inline assembly. If you don't use volatile then nothing > will tell the compiler that it can't optimize the code and move the > read/write across the macroized memfence. It is especially true on > platforms that don't actually need hardware memfences (like x86) since > in those cases calls to macro memfences will expand to nothing at all > and then you will have nothing in your code that tells anything about a > code-migration barrier. > > So is volatile sufficient - absolutely not. Portable? - hardly. > Is it necessary in certain cases - absolutely. Perhaps I was a bit too strong in my statement. I did intent to say "for portable uses". However, for future reference, what compilers of what versions on what platforms implement volatile with these semantics? I would like to research these claims to be better prepared in this discussion and future ones. Are any of these implementations not x86? These implementations really don't provide a sane threading interface and force the use of the volatile keyword for threading? Weird. I still must ask, really? That would mean that all shared state must be volatile qualified, including internal class members for shared data. Wouldn't that big a huge performance hit when the compiler can't optimize any of that? Could you even use prebuilt classes (which usually don't have volatile overloads) in the shared data, like say std::string, std::vector, std::map, etc.? Can you wrap this horrible threading interface into sane functions which provide the usual semantics instead of doing this horrible volatile hackery? That's what I would strongly suggest if possible. Finally, on x86s, not all memfences are no-ops, though perhaps we're using different definitions of memfences. Referencing JSR-133 Cookbook http://g.oswego.edu/dl/jmm/cookbook.html The "StoreLoad" memory barrier is not a no-op on x86. -- [ See http://www.gotw.ca/resources/clcm.htm for info about ] [ comp.lang.c++.moderated. First time posters: Do this! ]
From: Mathias Gaunard on 21 Mar 2010 06:28 On 21 mar, 08:09, Andy Venikov <swojchelo...(a)gmail.com> wrote: > It all depends on how memory barriers/fences are implemented. In the > same way that C++ standard doesn't talk about threads it doesn't talk > about memory fences. If a memfence call is implemented as a library > call, then yes, you will in essence get a compiler-level fence directive > as none of the compilers I know of are allowed to move the code across a > call to a library. But oftentimes memfences are implemented as macros > that expand to inline assembly. If you don't use volatile then nothing > will tell the compiler that it can't optimize the code and move the > read/write across the macroized memfence. Likewise, compilers do not move the code when it contains inline assembly, especially if that assembly contains memory fences... -- [ See http://www.gotw.ca/resources/clcm.htm for info about ] [ comp.lang.c++.moderated. First time posters: Do this! ]
From: Andy Venikov on 21 Mar 2010 06:32 Joshua Maurice wrote: >> So is volatile sufficient - absolutely not. Portable? - hardly. >> Is it necessary in certain cases - absolutely. > > Perhaps I was a bit too strong in my statement. I did intent to say > "for portable uses". > > However, for future reference, what compilers of what versions on what > platforms implement volatile with these semantics? I would like to > research these claims to be better prepared in this discussion and > future ones. Are any of these implementations not x86? These > implementations really don't provide a sane threading interface and > force the use of the volatile keyword for threading? Weird. > I'm sorry if I wasn't clear in my previous post, but I was talking about standard volatile behavior. The standard places a requirement on conforming implementations that: 1.9.6 The observable behavior of the abstract machine is its sequence of reads and writes to volatile data and calls to library I/O functions 1.9.7 Accessing an object designated by a volatile lvalue (3.10), modifying an object, calling a library I/O function, or calling a function that does any of those operations are all side effects, which are changes in the state of the execution environment. Evaluation of an expression might produce side effects. At certain specified points in the execution sequence called sequence points, all side effects of previous evaluations shall be complete and no side effects of subsequent evaluations shall have taken place 1.9.11 The least requirements on a conforming implementation are: � At sequence points, volatile objects are stable in the sense that previous evaluations are complete and subsequent evaluations have not yet occurred. That to me sounds like a complete enough requirement that compilers don't perform optimizations that produce "surprising" results in so far as observable behavior in an abstract (single-threaded) machine are concerned. This requirement happens to be very useful for multi-threaded programs that can augment volatile with hardware fences to produce meaningful results. > I still must ask, really? That would mean that all shared state must > be volatile qualified, including internal class members for shared > data. Wouldn't that big a huge performance hit when the compiler can't > optimize any of that? Could you even use prebuilt classes (which > usually don't have volatile overloads) in the shared data, like say > std::string, std::vector, std::map, etc.? Not at all! Most multi-threading issues are solved with mutexes, semaphores, conditional variables and such. All of these are library calls. That means that using volatile in those cases is not necessary. It's only when you get into more esotheric parallel computing problems where you'd like to avoid a heavy-handed approach of mutexes that you enter the realm of volatile. In normal multi-threading solved with regular means there is really no reason to use volatile. <snip> Thanks, Andy. -- [ See http://www.gotw.ca/resources/clcm.htm for info about ] [ comp.lang.c++.moderated. First time posters: Do this! ]
From: Leigh Johnston on 21 Mar 2010 15:03 "Andy Venikov" <swojchelowek(a)gmail.com> wrote in message news:ho5s8u$52u$1(a)news.eternal-september.org... >> I still must ask, really? That would mean that all shared state must >> be volatile qualified, including internal class members for shared >> data. Wouldn't that big a huge performance hit when the compiler can't >> optimize any of that? Could you even use prebuilt classes (which >> usually don't have volatile overloads) in the shared data, like say >> std::string, std::vector, std::map, etc.? > > Not at all! > Most multi-threading issues are solved with mutexes, semaphores, > conditional variables and such. All of these are library calls. That > means that using volatile in those cases is not necessary. It's only > when you get into more esotheric parallel computing problems where you'd > like to avoid a heavy-handed approach of mutexes that you enter the > realm of volatile. In normal multi-threading solved with regular means > there is really no reason to use volatile. Esoteric? I would have thought independent correctly aligned (and therefore atomic) x86 variable reads (fundamental types) without the use of a mutex are not uncommon making volatile not uncommon also on that platform (on VC++) at least. I have exactly one volatile in my entire codebase and that is such a variable. From MSDN (VC++) docs: "The volatile keyword is a type qualifier used to declare that an object can be modified in the program by something such as the operating system, the hardware, or a concurrently executing thread." That doesn't seem esoteric to me! :) /Leigh -- [ See http://www.gotw.ca/resources/clcm.htm for info about ] [ comp.lang.c++.moderated. First time posters: Do this! ]
From: Bo Persson on 22 Mar 2010 08:22
Leigh Johnston wrote: > "Andy Venikov" <swojchelowek(a)gmail.com> wrote in message > news:ho5s8u$52u$1(a)news.eternal-september.org... >>> I still must ask, really? That would mean that all shared state >>> must be volatile qualified, including internal class members for >>> shared data. Wouldn't that big a huge performance hit when the >>> compiler can't optimize any of that? Could you even use prebuilt >>> classes (which usually don't have volatile overloads) in the >>> shared data, like say std::string, std::vector, std::map, etc.? >> >> Not at all! >> Most multi-threading issues are solved with mutexes, semaphores, >> conditional variables and such. All of these are library calls. >> That means that using volatile in those cases is not necessary. >> It's only when you get into more esotheric parallel computing >> problems where you'd like to avoid a heavy-handed approach of >> mutexes that you enter the realm of volatile. In normal >> multi-threading solved with regular means there is really no >> reason to use volatile. > > Esoteric? I would have thought independent correctly aligned (and > therefore atomic) x86 variable reads (fundamental types) without > the use of a mutex are not uncommon making volatile not uncommon > also on that platform (on VC++) at least. I have exactly one > volatile in my entire codebase and that is such a variable. From > MSDN (VC++) docs: > "The volatile keyword is a type qualifier used to declare that an > object can be modified in the program by something such as the > operating system, the hardware, or a concurrently executing thread." > > That doesn't seem esoteric to me! :) > The esoteric thing is that this is a compiler specific extension, not something guaranteed by the language. Currently there are no threads at all in C++. Note that the largest part of the MSDN document is clearly marked "Microsoft Specific". It is in that part the release and aquire semantics are defined. Bo Persson -- [ See http://www.gotw.ca/resources/clcm.htm for info about ] [ comp.lang.c++.moderated. First time posters: Do this! ] |