Re: Question on using volatile in a return type
Ichthyostega wrote:
[...]
void func1 (volatile bool& flag) {
// init...
while (!flag && !err)
err = pthread_cond_wait (&cond, &mutex);
// ...
}
The "volatile" should give the compiler a hint not to employ
optimisations but fetch the value from the original location, where
it may have been changed by another thread meanwhile -- is this
correct?
Correct. Like const, the const/volatile in references/pointers to
const/volatile affects what can be done via the reference/pointer.
int i;
const int& c = i;
c = 1; // error
i = 2; // OK
volatile int& v = i;
v = 1;
v = 2; // generate code must write to v twice
i = 3; // generated code can eliminate this write to i
i = 4;
And: does the flag referred to have to be declared as volatile at
the original location? (usually somewhere in a class?). Or is it
sufficient to define the reference as volatile bool& ?
Original object can be non-volatile, just as with const.
Now, assumed I want to use a functor instead of the bool flag.
What would be the correct and the "best" way to define it?
To be equivalent, use volatile appropriately on any objects the
functor uses.
class Check1 {
bool operator() () { ... }
}
class Check2 {
volatile bool operator() () { ... }
}
class Check3 {
volatile bool& operator() () { ... }
}
My understanding is that for Check3 the "volatile" is necessary, is this
correct? But Check1 should be ok, because it's returning a value and it will
actually be re-invoked in each loop iteration?
Depends on what the ... is. Assuming something like
class Check1 {
volatile bool& b;
bool operator() () { return b; }
};
Then it's fine, since in accessing b the compiler is forced to read.
The same would work for the other two as well, with their unnecessary
volatile and bool.
If you instead had a reference-to-non-volatile,
class Check1 {
bool& b;
bool operator() () { return b; }
};
Check1 and Check2 could fail, since the compiler could avoid
re-reading the object referred to by b. But Check3 would work, since
the caller would be accessing the object via a volatile path:
class Check3 {
bool& b;
volatile bool& operator() () { return b; }
};
void func1 (Check3 flag)
{
while (!flag() && !err)
...
}
And besides, would you consider the definition within Check2 good practice,
bad practice, expressive, superfluous, ....?
From what little I know about multi-threaded (including multi-core and
multi-processor) coding, volatile alone is insufficient in most cases,
since in the absence of thread synchronization operations, the order
of memory writes in one thread can differ from the order they're seen
by another thread. That is, I believe that something like
volatile sig_atomic_t x, y;
void thread_1()
{
while ( x == 0 ) { }
cout << y;
}
void thread_2()
{
y = 1;
x = 1;
}
could print 0, even though thread_2 writes to y first (through a
volatile variable). What do you know, the example on Wikipedia is the
same: http://en.wikipedia.org/wiki/Memory_barrier
BTW, PGP-signing your messages adds lots of cruft that clutters your
postings.