From: Joshua Maurice on
On Mar 17, 8:16 pm, "Leigh Johnston" <le...(a)i42.co.uk> wrote:
> "Joshua Maurice" <joshuamaur...(a)gmail.com> wrote in message
>
> news:db73b48d-1504-473d-bb4f-9c6243c6372a(a)l12g2000prg.googlegroups.com...
> <snip>
>
> >> > Well, for starters, why are you using the volatile keyword? Do you
> >> > think it's a portable threading construct? It's not. volatile in C and
> >> > C++ has nothing to do with threading. The C and C++ standards do not
> >> > talk about threads, so anything they say about volatile is irrelevant.
> >> > By POSIX, volatile means nothing special for threading. (The Microsoft
> >> > compiler under certain versions does claim to make it like a mutex
> >> > acquire and release, but let's just ignore this bad form for now. Use
> >> > boost or ACE or some portable library if you need atomic functions, or
> >> > wait for the new C++ standard. At worst, wrap volatile yourself to not
> >> > litter your code with a not portable construct + usage.)
>
> >> This makes me very confused. I've always been taught to use the volatile
> >> keyword in front of variables that can be accessed from several threads.
>
> > I'm sorry that you were taught incorrectly. I suggest reading the
> > paper:
> > http://www.aristeia.com/Papers/DDJ_Jul_Aug_2004_revised.pdf
> > It's a much more thorough description of modern threading in C++, and
> > specifically the volatile keyword. Any programmer who uses threads
> > should read this paper and understand its implications.
>
> > This is a very common misconception. I would guess that it started
> > from poor teaching in schools and elsewhere. In the programming
> > courses I took in my college, I was taught a very simple and naive
> > threading model, just as most physicists are taught Newtonian
> > mechanics, except unlike the physicists and General Relativity and
> > quantum mechanics, I was never taught this naive threading model was
> > actually incorrect, that it's not how POSIX and WIN32 threads actually
> > work. I believe that most people who are taught threading are taught
> > this naive model first and never taught any better, and it's simply
> > perpetuated itself due to lack of understanding. This naive model is
> > part of the naive model of computers in general as executing source
> > code instructions faithfully, in order, without any changes. However,
> > in the real world, C++ (and other industry programming languages) have
> > the "as-if" rule which allows or is interpreted as allowing reordering
> > and changing of instructions of a single thread as long as the result
> > of that thread \in isolation\ is the same before and after the
> > modifications. This is the allowance for basically all optimizations.
> > To do otherwise in the presence of multiple threads would be \way\ too
> > great of a performance hit.
>
> > Coming full circle, volatile in C and C++ was not intended to
> > guarantee a global order across threads, no other standard such as
> > POSIX defines it as such (though visual studios compiler may), and
> > most compilers implement volatile as not guaranteeing a global order
> > across threads. Thus, volatile is not a portable threading construct
> > in C or C++.
>
> You are incorrect to claim that volatile as defined by the current C++
> standard has no use in multi-threaded programming. Whilst volatile does not
> guarantee atomicity nor memory ordering across multiple threads the fact
> that it prevents the compiler from caching vales in registers is useful and
> perhaps essential. From Modern C++ Design:
>
> "The volatile qualifier applied to a type tells the compiler that values of
> that type might be changed by multiple threads. Knowing this, the compiler
> avoids some optimizations (such as keeping values in internal registers)
> that would make multithreaded code run erratically".
>
> Just because there is no mention of threads in the current C++ standard does
> not mean that the vast majority of C++ compilers don't implement volatile in
> such a way that it is useful in multi-threaded designs.

I'm sorry. From my experience, and all that I have read, you are
incorrect. "Modern C++ Design" is also incorrect in this regard.


> 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.


As long as we're using appeal to authority (such as when you quoted
Modern C++ Design), I'll do the same. You appealed to the authority of
the well known book "Modern C++ Design", written in 2001 by Andrei
Alexandrescu. I appealed to the paper "C++ And The Perils Of Double-
Checked Locking":
http://www.aristeia.com/Papers/DDJ_Jul_Aug_2004_revised.pdf
written by, (wait for it), Andrei Alexandrescu, in the year 2004 (and
also co-authored by Scott Meyers). The paper goes into great detail
dispelling this myth that volatile is a useful portable threading
construct. I suggest not citing an outdated resource which is directly
contradicted in a paper later written \by the same person\, which also
happened to be cited in the \same post\ to which you replied, quoted,
and claimed incorrect.

I can't recall for the life of me where I read it, but I seem to
recall Andrei admitting that he misunderstand volatile, and learned of
the error of his ways, possibly in conjunction with "C++ And The
Perils Of Double-Checked Locking".

Continuing the appeal to authority, we have these papers written by
quite famous people as well:
>From the standard committee's website, written by Hans Boehm & Nick
Maclaren:
http://www.open-std.org/jtc1/sc22/wg21/docs/papers/2006/n2016.html
which goes into great detail on this discussion.

We also have the comp.programming.threads FAQ which also agrees
numerous times:
http://www.lambdacs.com/cpt/FAQ.html#Q56
http://www.lambdacs.com/cpt/FAQ.html#Q162

A random intel blog found via google whose authority and accuracy I
cannot quickly verify, but I include it here for fun and because it
references the paper by Hans Boehm linked above.

http://software.intel.com/en-us/blogs/2007/11/30/volatile-almost-useless-for-multi-threaded-programming/

I can quote numerous other blogs, compiler docs, etc., which all
explain that volatile is not a portable threading construct, and
probably never will be in C nor C++. (Again, do note that certain
windows compilers do actually give volatile mutex acquire and release
semantics. I merely claimed "not portable". I did not claim "no system
does this", nor "It won't work if you try it". )


As your argument was solely appeal to authority, I cannot reply in any
other additional way besides to:
A- quote more authority
B- repeat my (perhaps unfounded) second hand information that volatile
in fact on most current implementations does not make a global
ordering of reads and writes.
C- repeat my previous arguments that volatile does not guarantee a
global ordering of reads and writes in any standard I can find, unlike
mutexes, memory barriers, etc. Also, even if you could find a
(portable) standard which stated that in C or C++ a volatile read or
write "won't be cached" is not sufficient to make it a useful portable
threading construct. Reason 1 is not cache coherent systems. Reason 2
is your "standard" will not make a reference to non-volatile reads and
writes, and thus they may be reordered relative to the volatile reads
and writes. (Explained in the C++ And The Perils Of Double-Checked
Locking paper.)


--
[ See http://www.gotw.ca/resources/clcm.htm for info about ]
[ comp.lang.c++.moderated. First time posters: Do this! ]

From: Herb Sutter on
On Wed, 17 Mar 2010 21:16:23 CST, "Leigh Johnston" <leigh(a)i42.co.uk>
wrote:
>You are incorrect to claim that volatile as defined by the current C++
>standard has no use in multi-threaded programming. Whilst volatile does not
>guarantee atomicity nor memory ordering across multiple threads the fact
>that it prevents the compiler from caching vales in registers is useful and
>perhaps essential.

Yes, volatile does that. Unfortunately, that is necessary but not
sufficient for inter-thread communication to work correctly. Volatile
is for hardware access; std::atomic<T> is for multithreaded code
synchronized without mutexes.

Also, to add further confusion, in Java and C# volatile _is_ for
inter-thread communication. C/C++ volatile != Java/C# volatile.

For a little more on this, see:

http://herbsutter.wordpress.com/2009/01/12/effective-concurrency-volatile-vs-volatile/


> From Modern C++ Design:
>
>"The volatile qualifier applied to a type tells the compiler that values of
>that type might be changed by multiple threads. Knowing this, the compiler
>avoids some optimizations (such as keeping values in internal registers)
>that would make multithreaded code run erratically".

Actually IIRC Andrei has recanted on that. (Andrei, please correct me
if I'm wrong.) In some of his articles, what he was really doing was
to hijack (er, I mean, "reuse") the volatile keyword as a handy
mostly-unused tag in the type system he could use as a hook to
overload and get other effects, which was a little confusing because
it wasn't stated quite that way.

Herb
---
Herb Sutter (herbsutter.wordpress.com) (www.gotw.ca)

Convener, ISO/IEC JTC1/SC22/WG21 (C++) (www.gotw.ca/iso)
Architect, Microsoft Visual C++ (www.gotw.ca/microsoft)

--
[ See http://www.gotw.ca/resources/clcm.htm for info about ]
[ comp.lang.c++.moderated. First time posters: Do this! ]

From: Andrei Alexandrescu on
On 03/17/2010 10:16 PM, Leigh Johnston wrote:
>
>
> "Joshua Maurice" <joshuamaurice(a)gmail.com> wrote in message
> news:db73b48d-1504-473d-bb4f-9c6243c6372a(a)l12g2000prg.googlegroups.com...
> <snip>
>>> > Well, for starters, why are you using the volatile keyword? Do you
>>> > think it's a portable threading construct? It's not. volatile in C and
>>> > C++ has nothing to do with threading. The C and C++ standards do not
>>> > talk about threads, so anything they say about volatile is irrelevant.
>>> > By POSIX, volatile means nothing special for threading. (The Microsoft
>>> > compiler under certain versions does claim to make it like a mutex
>>> > acquire and release, but let's just ignore this bad form for now. Use
>>> > boost or ACE or some portable library if you need atomic functions, or
>>> > wait for the new C++ standard. At worst, wrap volatile yourself to not
>>> > litter your code with a not portable construct + usage.)
>>>
>>> This makes me very confused. I've always been taught to use the volatile
>>> keyword in front of variables that can be accessed from several threads.
>>
>> I'm sorry that you were taught incorrectly. I suggest reading the
>> paper:
>> http://www.aristeia.com/Papers/DDJ_Jul_Aug_2004_revised.pdf
>> It's a much more thorough description of modern threading in C++, and
>> specifically the volatile keyword. Any programmer who uses threads
>> should read this paper and understand its implications.
>>
>> This is a very common misconception. I would guess that it started
>> from poor teaching in schools and elsewhere. In the programming
>> courses I took in my college, I was taught a very simple and naive
>> threading model, just as most physicists are taught Newtonian
>> mechanics, except unlike the physicists and General Relativity and
>> quantum mechanics, I was never taught this naive threading model was
>> actually incorrect, that it's not how POSIX and WIN32 threads actually
>> work. I believe that most people who are taught threading are taught
>> this naive model first and never taught any better, and it's simply
>> perpetuated itself due to lack of understanding. This naive model is
>> part of the naive model of computers in general as executing source
>> code instructions faithfully, in order, without any changes. However,
>> in the real world, C++ (and other industry programming languages) have
>> the "as-if" rule which allows or is interpreted as allowing reordering
>> and changing of instructions of a single thread as long as the result
>> of that thread \in isolation\ is the same before and after the
>> modifications. This is the allowance for basically all optimizations.
>> To do otherwise in the presence of multiple threads would be \way\ too
>> great of a performance hit.
>>
>>
>> Coming full circle, volatile in C and C++ was not intended to
>> guarantee a global order across threads, no other standard such as
>> POSIX defines it as such (though visual studios compiler may), and
>> most compilers implement volatile as not guaranteeing a global order
>> across threads. Thus, volatile is not a portable threading construct
>> in C or C++.
>>
>
> You are incorrect to claim that volatile as defined by the current C++
> standard has no use in multi-threaded programming. Whilst volatile does not
> guarantee atomicity nor memory ordering across multiple threads the fact
> that it prevents the compiler from caching vales in registers is useful and
> perhaps essential. From Modern C++ Design:
>
> "The volatile qualifier applied to a type tells the compiler that values of
> that type might be changed by multiple threads. Knowing this, the compiler
> avoids some optimizations (such as keeping values in internal registers)
> that would make multithreaded code run erratically".
>
> Just because there is no mention of threads in the current C++ standard
> does
> not mean that the vast majority of C++ compilers don't implement
> volatile in
> such a way that it is useful in multi-threaded designs.
>
> 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.
>
> The goal when writing multi-threaded code though should be to minimize
> shared state the result of which should mean very few volatile objects in
> your code.
>
> /Leigh

I apologize for my handling of the volatile qualifier stronger than I
should have in "Modern C++ Design". My understanding of the matters at
the time was incomplete; volatile was intended to deal with interrupts,
not threads, and in a very system-dependent manner.

You are essentially right that some compilers do implement volatile to
help with threads. As an example, GNU C and C++ ascribe thread-related
meaning to volatile, but only with asm:

http://www.ibiblio.org/gferg/ldp/GCC-Inline-Assembly-HOWTO.html#ss5.4

(I'm not sure whether GNU defines volatile as a qualifier to help with
thteads.)

But by and large that's not sufficient to make sure things do work, and
they will never work portably. Here's a good article on the topic:

http://software.intel.com/en-us/blogs/2007/11/30/volatile-almost-useless-for-multi-threaded-programming/

entitled eloquently "Volatile: Almost Useless for Multi-Threaded
Programming". And here's another entitled even stronger 'Why the
"volatile" type class should not be used':

http://kernel.org/doc/Documentation/volatile-considered-harmful.txt

The presence of the volatile qualifier in Loki is at best helpful but
never a guarantee of correctness. I recommend Scott and my article on
the topic, which was mentioned earlier in this thread:

http://www.aristeia.com/Papers/DDJ_Jul_Aug_2004_revised.pdf

Bottom line: using volatile with threads is almost always a red herring.


Andrei

--
[ See http://www.gotw.ca/resources/clcm.htm for info about ]
[ comp.lang.c++.moderated. First time posters: Do this! ]

From: Leigh Johnston on
"Herb Sutter" <herb.sutter(a)gmail.com> wrote in message
news:g4l4q5dr3sgl1ormesv4lugbton262k0j8(a)4ax.com...
> On Wed, 17 Mar 2010 21:16:23 CST, "Leigh Johnston" <leigh(a)i42.co.uk>
> wrote:
>>You are incorrect to claim that volatile as defined by the current C++
>>standard has no use in multi-threaded programming. Whilst volatile does
>>not
>>guarantee atomicity nor memory ordering across multiple threads the fact
>>that it prevents the compiler from caching vales in registers is useful
>>and
>>perhaps essential.
>
> Yes, volatile does that. Unfortunately, that is necessary but not
> sufficient for inter-thread communication to work correctly. Volatile
> is for hardware access; std::atomic<T> is for multithreaded code
> synchronized without mutexes.
>

That was my point, volatile whilst not a solution in itself is a "part" of a
solution for multi-threaded programming when using a C++ (current standard)
optimizing compiler:

thread A:
finished = false;
spawn_thread_B();
while(!finished)
{
/* do work */
}

thread B:
/* do work */
finished = true;

If finished is not volatile and compiler optimizations are enabled thread A
may loop forever.

/Leigh



--
[ See http://www.gotw.ca/resources/clcm.htm for info about ]
[ comp.lang.c++.moderated. First time posters: Do this! ]

From: Leigh Johnston on


"Joshua Maurice" <joshuamaurice(a)gmail.com> wrote in message
news:900580c6-c55c-46ec-b5bc-1a9a2f0d76f5(a)w9g2000prb.googlegroups.com...
<snip>
>> You are incorrect to claim that volatile as defined by the current C++
>> standard has no use in multi-threaded programming. Whilst volatile does
>> not
>> guarantee atomicity nor memory ordering across multiple threads the fact
>> that it prevents the compiler from caching vales in registers is useful
>> and
>> perhaps essential. From Modern C++ Design:
>>
>> "The volatile qualifier applied to a type tells the compiler that values
>> of
>> that type might be changed by multiple threads. Knowing this, the
>> compiler
>> avoids some optimizations (such as keeping values in internal registers)
>> that would make multithreaded code run erratically".
>>
>> Just because there is no mention of threads in the current C++ standard
>> does
>> not mean that the vast majority of C++ compilers don't implement volatile
>> in
>> such a way that it is useful in multi-threaded designs.
>
> I'm sorry. From my experience, and all that I have read, you are
> incorrect. "Modern C++ Design" is also incorrect in this regard.
>
>
>> 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.
>

No. Memory barriers are not sufficient if your optimizing compiler is
caching the value in a register: the CPU is not aware that the register is
referring to data being revealed by the memory barrier. I never said
volatile was a panacea but is something that is probably required when using
an optimizing compiler. If your C++ compiler has memory barrier intrinsics
it might be able to ensure volatile is not required but this is also
non-standard.

/Leigh


--
[ See http://www.gotw.ca/resources/clcm.htm for info about ]
[ comp.lang.c++.moderated. First time posters: Do this! ]