Connecting Tech Pros Worldwide Forums | Help | Site Map

Volatile classes

mlimber
Guest
 
Posts: n/a
#1: Nov 30 '05
I am using placement new to locate a shared data structure at a
particular location in shared memory. The problem is that when I access
the data on one of the two processors sharing it, I don't get the same
values seen by the other processor (which uses a cache-less access
method, unlike what follows). Here's a reduced example:

struct SharedData
{
enum Item { A=0, B=1 };

// Note volatile:
int Get( Item i ) const volatile { return data_[ i ]; }
// ...
private:
int data_[ 2 ];
};

void Foo()
{
void *const addr = reinterpret_cast<void*>( 0x8000 );
volatile SharedData *const data = new( addr ) SharedData;

const int a1 = data->Get( SharedData::A );
const int a2 = data->Get( SharedData::A );
// ...
}

The problem is that a1 and a2 may not be the same because the second
processor may modify the value - a classic case for the volatile
qualifier. The C way to handle this would be something like:

volatile int* const a = reinterpret_cast<volatile int*>( 0x8000 );
volatile int* const b = reinterpret_cast<volatile int*>( 0x8004 );

I thought, however, that applying volatile to the pointer-type in Foo()
and the appropriate member functions in SharedData would do basically
the same thing - namely, force all the data members of SharedData to be
volatile. Am I mistaken?

Cheers! --M


peter steiner
Guest
 
Posts: n/a
#2: Nov 30 '05

re: Volatile classes



mlimber wrote:[color=blue]
> I am using placement new to locate a shared data structure at a
> particular location in shared memory. The problem is that when I access
> the data on one of the two processors sharing it, I don't get the same
> values seen by the other processor (which uses a cache-less access
> method, unlike what follows). Here's a reduced example:
>
> struct SharedData
> {
> enum Item { A=0, B=1 };
>
> // Note volatile:
> int Get( Item i ) const volatile { return data_[ i ]; }
> // ...
> private:
> int data_[ 2 ];
> };
>
> void Foo()
> {
> void *const addr = reinterpret_cast<void*>( 0x8000 );
> volatile SharedData *const data = new( addr ) SharedData;
>
> const int a1 = data->Get( SharedData::A );
> const int a2 = data->Get( SharedData::A );
> // ...
> }
>
> The problem is that a1 and a2 may not be the same because the second
> processor may modify the value - a classic case for the volatile
> qualifier. The C way to handle this would be something like:
>
> volatile int* const a = reinterpret_cast<volatile int*>( 0x8000 );
> volatile int* const b = reinterpret_cast<volatile int*>( 0x8004 );
>
> I thought, however, that applying volatile to the pointer-type in Foo()
> and the appropriate member functions in SharedData would do basically
> the same thing - namely, force all the data members of SharedData to be
> volatile. Am I mistaken?[/color]

i don't have the standard at hand, but according to the following link,
a fantastic article about this topic by alexandrescu, it does.

http://www.cuj.com/documents/s=7998/...p1902alexandr/

to me this looks like either your memory is modified by other effects
or this is a compiler bug.

-- peter

Gianni Mariani
Guest
 
Posts: n/a
#3: Nov 30 '05

re: Volatile classes


mlimber wrote:
....[color=blue]
> The problem is that a1 and a2 may not be the same because the second
> processor may modify the value - a classic case for the volatile
> qualifier. The C way to handle this would be something like:
>
> volatile int* const a = reinterpret_cast<volatile int*>( 0x8000 );
> volatile int* const b = reinterpret_cast<volatile int*>( 0x8004 );
>
> I thought, however, that applying volatile to the pointer-type in Foo()
> and the appropriate member functions in SharedData would do basically
> the same thing - namely, force all the data members of SharedData to be
> volatile. Am I mistaken?[/color]

What do you think volatile means ?

I don't understand what the "problem" is.
mlimber
Guest
 
Posts: n/a
#4: Nov 30 '05

re: Volatile classes


Gianni Mariani wrote:[color=blue]
> mlimber wrote:
> ...[color=green]
> > The problem is that a1 and a2 may not be the same because the second
> > processor may modify the value - a classic case for the volatile
> > qualifier. The C way to handle this would be something like:
> >
> > volatile int* const a = reinterpret_cast<volatile int*>( 0x8000 );
> > volatile int* const b = reinterpret_cast<volatile int*>( 0x8004 );
> >
> > I thought, however, that applying volatile to the pointer-type in Foo()
> > and the appropriate member functions in SharedData would do basically
> > the same thing - namely, force all the data members of SharedData to be
> > volatile. Am I mistaken?[/color]
>
> What do you think volatile means ?[/color]

It is compiler specific, but it means that the compiler should not do
any fancy optimizations to the data at hand. That means, for instance,
not caching a variable in a register even though the code doesn't
appear to change it. By using volatile, the programmer is indicating
that the value could change due to something outside the program (e.g.
another thread or process or a hardware device).
[color=blue]
> I don't understand what the "problem" is.[/color]

It appears that my volatile data is not read fresh at each access.
Consequently, one processor incorrectly reads 0 while the other
correctly reads 1. (Correctness is determined by what the memory
actually holds.)

Cheers! --M

Kaz Kylheku
Guest
 
Posts: n/a
#5: Nov 30 '05

re: Volatile classes


mlimber wrote:[color=blue]
> I am using placement new to locate a shared data structure at a
> particular location in shared memory. The problem is that when I access
> the data on one of the two processors sharing it, I don't get the same
> values seen by the other processor (which uses a cache-less access
> method, unlike what follows).[/color]

There is nothing in the C++ language that can help you. The C++
standard doesn't require any support for multiprocessing.
[color=blue]
> The problem is that a1 and a2 may not be the same because the second
> processor may modify the value - a classic case for the volatile
> qualifier.[/color]

That is not what volatile is intended for.

The intent of volatile is to suppress the /language implementation's/
caching optimizations. Not those of the entire data processor. Caching
optimizations are deviations from the abstract machine, whereby objects
that are modified are not actually updated at the next sequence point.

There is always /some/ caching going on. If you load a value into
processor, and do something with it, then compute a new value, for a
brief time, the computed value is out of sync with the storage object
that it's destined for.

The volatile qualifier comes from ANSI C. According to ANSI C, an
asynchronous signal handler may write a value to a static object of
type volatile sig_atomic_t. The idea is that mainline code which checks
that value will see the modification, rather than keep referring to a
cached copy. This example doesn't even involve multiple threads, never
mind processors. You see, the caching optimizations performed by
compilers can affect the interaction between single-threaded code and
its asynchronous interrupts, or threads that are scheduled on just one
processor that has a single, coherent view of its memory.

Other than making this case work (volatile sig_atomic_t and signal
handler), a compiler can ignore volatile (provided that it emits a
diagnostic about any diagnosable rule violation related to the use of
the keyword).

At best, if your compiler properly supports the spirit of the intended
meaning of volatile, its use will ensure that when you store to the
object, the value is actually written to memory no later than the next
sequence point, and when you read from the object, the latest value is
retrieved.

If you need further synchronization at the hardware level, you have to
insert the machine instructions yourself: memory barriers, cache
flushes, whatever.
[color=blue]
> I thought, however, that applying volatile to the pointer-type in Foo()
> and the appropriate member functions in SharedData would do basically
> the same thing - namely, force all the data members of SharedData to be
> volatile. Am I mistaken?[/color]

Nope. The qualifier on a member function is essentially inherited by
the this pointer. If the function is const, the this pointer refers to
a const-qualified object, etc. This part is right.

Kaz Kylheku
Guest
 
Posts: n/a
#6: Nov 30 '05

re: Volatile classes


mlimber wrote:[color=blue]
> Gianni Mariani wrote:[color=green]
> > What do you think volatile means ?[/color]
>
> It is compiler specific, but it means that the compiler should not do
> any fancy optimizations to the data at hand.[/color]

Multiprocessor coherency problems are not caused by optimizations that
the compiler does.

Josh Mcfarlane
Guest
 
Posts: n/a
#7: Nov 30 '05

re: Volatile classes


mlimber wrote:[color=blue]
> It is compiler specific, but it means that the compiler should not do
> any fancy optimizations to the data at hand. That means, for instance,
> not caching a variable in a register even though the code doesn't
> appear to change it. By using volatile, the programmer is indicating
> that the value could change due to something outside the program (e.g.
> another thread or process or a hardware device).
>[color=green]
> > I don't understand what the "problem" is.[/color]
>
> It appears that my volatile data is not read fresh at each access.
> Consequently, one processor incorrectly reads 0 while the other
> correctly reads 1. (Correctness is determined by what the memory
> actually holds.)[/color]

Have you tried adding volatile to the actual array rather than the
function call?

Gianni Mariani
Guest
 
Posts: n/a
#8: Dec 1 '05

re: Volatile classes


mlimber wrote:[color=blue]
> Gianni Mariani wrote:[/color]
[color=blue]
>[color=green]
>>I don't understand what the "problem" is.[/color]
>
>
> It appears that my volatile data is not read fresh at each access.
> Consequently, one processor incorrectly reads 0 while the other
> correctly reads 1. (Correctness is determined by what the memory
> actually holds.)[/color]

OK - This one is easy to check to see - look at the compiled
instructions and see if the generated code is actually performing the reads.

If I read it correctly, then yes, the _data array should be volatile in
this case.

Which compiler ?
mlimber
Guest
 
Posts: n/a
#9: Dec 1 '05

re: Volatile classes


Gianni Mariani wrote:[color=blue]
> mlimber wrote:[color=green]
> > Gianni Mariani wrote:[/color]
>[color=green]
> >[color=darkred]
> >>I don't understand what the "problem" is.[/color]
> >
> >
> > It appears that my volatile data is not read fresh at each access.
> > Consequently, one processor incorrectly reads 0 while the other
> > correctly reads 1. (Correctness is determined by what the memory
> > actually holds.)[/color]
>
> OK - This one is easy to check to see - look at the compiled
> instructions and see if the generated code is actually performing the reads.
>
> If I read it correctly, then yes, the _data array should be volatile in
> this case.
>
> Which compiler ?[/color]

Texas Instruments 5.1.0, which I think uses the EDG front-end.

More to come when I try the suggestions given here...

Cheers! --M

mlimber
Guest
 
Posts: n/a
#10: Dec 1 '05

re: Volatile classes


Gianni Mariani wrote:[color=blue]
> mlimber wrote:[color=green]
> > Gianni Mariani wrote:[/color]
>[color=green]
> >[color=darkred]
> >>I don't understand what the "problem" is.[/color]
> >
> >
> > It appears that my volatile data is not read fresh at each access.
> > Consequently, one processor incorrectly reads 0 while the other
> > correctly reads 1. (Correctness is determined by what the memory
> > actually holds.)[/color]
>
> OK - This one is easy to check to see - look at the compiled
> instructions and see if the generated code is actually performing the reads.
>
> If I read it correctly, then yes, the _data array should be volatile in
> this case.
>
> Which compiler ?[/color]

Upon further testing, the compiler seems to be doing its job correctly
and my code works as expected if I disable the user-configurable
hardware cache. Since I want to use the cache in the production code,
however, I'll need to look into the platform-specific details of making
things work with the cache enabled.

Cheers! --M

Closed Thread