Groups | Search | Server Info | Keyboard shortcuts | Login | Register [http] [https] [nntp] [nntps]


Groups > comp.programming.threads > #1817

Re: forcing the compiler to reload from memory with c++0x

From Anthony Williams <anthony.ajw@gmail.com>
Newsgroups comp.programming.threads
Subject Re: forcing the compiler to reload from memory with c++0x
References (6 earlier) <947b33d5-2509-4f0c-9256-a7c3de35578e@24g2000yqa.googlegroups.com> <87mxmlxxry.fsf@justsoftwaresolutions.co.uk> <ihv8t6$bmr$1@news.eternal-september.org> <87oc6yxdcw.fsf@justsoftwaresolutions.co.uk> <ii745u$5q3$1@news.eternal-september.org>
Date 2011-02-01 08:24 +0000
Message-ID <87sjw8w4b5.fsf@justsoftwaresolutions.co.uk> (permalink)
Organization CNNTP

Show all headers | View raw


Andy Venikov <swojchelowek@gmail.com> writes:

> On 1/30/2011 4:58 PM, Anthony Williams wrote:
> <snip>
>
>> There are no guarantees about how quickly a given thread runs, so it
>> could be suspended for arbitrary amounts of time at arbitrary points.
>>
>> If the value of a_int is ever set to non-zero then the compiler is free
>> to omit the loop, since relaxed operations can read future values, so it
>> can assume that it read the non-zero future value. It has to be careful
>> not to invalidate modifcation orders, though --- future reads of a_int
>> from the same thread must read either the non-zero value that meant the
>> loop was omitted, or a later value in the modification order of a_int.
>>
>> This could be achieved by having a_int.get() block until it knew what
>> that non-zero value was.
>>
>> If the compiler does not know if a_int is ever set to non-zero, then it
>> must schedule at least one read of a_int. If it enters the loop, then it
>> must perform further reads of a_int as required by memory ordering
>> constraints on other variables. If there are no such constraints, then
>> it only need issue another read in some finite amount of time (which
>> could be large).
>>
> <snip>
>
> What I was trying to get at was how to force the compiler to treat my
> my code as-is. (I know this is not a correct way of putting it, but
> I'm just at a loss of how to better describe that).
> Before, it used to be accomplished with the use of volatile. If I had
>
> volatile int n;
> n = 1;
> n = 2;
>
> then all the compilers would generate object code that would have two
> store instruction. The hardware could do further damage to that, but
> at least at the compiler lever volatile could be used for that, even
> though we all know how evil it is. volatile was the defacto "do as
> told" directive.

Yes, and it still is: volatile writes are "observable behaviour" ---
volatile writes and I/O are the only required results of a C++ program.

> Here you mention about setting a_int to non-zero first. But as I
> understand, currently c++0x compiler can optimize-out even the endless
> loop:
>
> for(;;) {}
>
> http://groups.google.com/group/comp.lang.c++.moderated/browse_frm/thread/66520f133423e6dd

Yes, endless loops can be optimized out under some circumstances. The
compiler can't just remove all of them, though. The wording that allows
this is primarily there so that optimizers can move writes down across a
loop, even if that loop is potentially infinite. 

> So, it doesn't even matter what's in a_int, as long as the compiler
> thinks there aren't any observable side-effects. Is reading an atomic
> value in relaxed or acquire mode considered a side-effect? Will adding
> a fence in the body of the loop be considered a side effect? That was
> my question.

The compiler can do any optimization that yields a sequence of volatile
writes and I/O that is permissible under the rules of the abstract
machine. If you write a program to find a bunch of primes, the compiler
can do that at compile time, and produce a program that just prints
those primes (std::cout<<"2 3 5 7 11 ".....), if it detects that this is
what you are doing.

The compiler can thus omit atomic operations only if it can prove that
this makes no difference to the observable behaviour. e.g. if an I/O
statement is protected by an atomic read, the compiler must issue the
read unless it can prove a possible value for that read.

You can of course make your atomic variables volatile too, and then they
DO become observable behaviour.

> The reason I ask is that a LOT of lock-free algorithms rely on the
> following idiom:
>
> Node * pLocalCurrent = sharedHead; //"volatile" read
> Node * pLocalNext = pLocalCurrent->next; //another "volatile" read
>
> if (pLocalCurrent == sharedHead)
> {
>    //Here we can assume that pLocalNext is valid
> }
>
>
> Before, for this code to work properly on most compilers, I would have
> to declare sharedHead and the next member of Node as volatile. I would
> also have to use a LoadLoad barrier after the second line.
> Will C++0x's atomics make my day easier without relying on some
> potentially UB like volatiles?

For this to work under C++0x you will need to use atomics for sharedHead
and next. You will probably also need memory_order_consume or stronger
on at least one of the loads.

The compiler is allowed to optimize out the second read of sharedHead
and the comparison, and always run the body of the if. This is because
this is indistinguishable from the case that this thread runs solo for
this portion of the code, with any thread that might write to sharedHead
being suspended.

The compiler cannot *omit* the if without issuing a second read for the
comparison.

If you make your atomics volatile as well then the compiler must issue
the reads and writes in all cases.

Anthony
-- 
Author of C++ Concurrency in Action     http://www.stdthread.co.uk/book/
just::thread C++0x thread library             http://www.stdthread.co.uk
Just Software Solutions Ltd       http://www.justsoftwaresolutions.co.uk
15 Carrallack Mews, St Just, Cornwall, TR19 7UL, UK. Company No. 5478976

Back to comp.programming.threads | Previous | NextPrevious in thread | Next in thread | Find similar


Thread

Re: forcing the compiler to reload from memory with c++0x Andy Venikov <swojchelowek@gmail.com> - 2011-01-31 14:56 -0500
  Re: forcing the compiler to reload from memory with c++0x Anthony Williams <anthony.ajw@gmail.com> - 2011-02-07 22:13 +0000
    Re: forcing the compiler to reload from memory with c++0x Andy Venikov <swojchelowek@gmail.com> - 2011-02-07 17:54 -0500
  Re: forcing the compiler to reload from memory with c++0x Alexander Terekhov <terekhov@web.de> - 2011-02-04 16:39 +0100
    Re: forcing the compiler to reload from memory with c++0x Anthony Williams <anthony.ajw@gmail.com> - 2011-02-04 17:52 +0000
  Re: forcing the compiler to reload from memory with c++0x Anthony Williams <anthony.ajw@gmail.com> - 2011-02-04 08:56 +0000
    Re: forcing the compiler to reload from memory with c++0x Andy Venikov <swojchelowek@gmail.com> - 2011-02-06 23:23 -0500
  Re: forcing the compiler to reload from memory with c++0x Andy Venikov <swojchelowek@gmail.com> - 2011-02-03 17:43 -0500
    Re: forcing the compiler to reload from memory with c++0x Anthony Williams <anthony.ajw@gmail.com> - 2011-02-04 09:04 +0000
    Re: forcing the compiler to reload from memory with c++0x Joshua Maurice <joshuamaurice@gmail.com> - 2011-02-03 15:54 -0800
    Re: forcing the compiler to reload from memory with c++0x Andy Venikov <swojchelowek@gmail.com> - 2011-02-03 17:58 -0500
  Re: forcing the compiler to reload from memory with c++0x Anthony Williams <anthony.ajw@gmail.com> - 2011-02-01 08:24 +0000
    Re: forcing the compiler to reload from memory with c++0x Anthony Williams <anthony.ajw@gmail.com> - 2011-02-04 08:47 +0000
    Re: forcing the compiler to reload from memory with c++0x Andy Venikov <swojchelowek@gmail.com> - 2011-02-03 13:52 -0500

csiph-web