Re: Doug Harrison, please! by Doug
Doug
Sat Feb 07 14:02:11 CST 2004
fh1996 wrote:
>Thanks to everyone who answered my questions about SEH, specifically
>"volatile" one!
>(Please see thread: SEH and standard C++ exceptions)
>
>I have some more questions, which is regarding Doug Harrison's post:
>
>// Assuming everyone observes the locking protocol, this approach
>// would work on all hardware, even weird architectures like Sparc
>// and others which require memory barriers:
>
>bool x = true; // As above, just non-volatile
>
>for (;;)
>{
> lock(mx);
> bool y = x;
> unlock(mx);
> if (!y)
> break;
> whatever;
>}
>
>This is new and interesting to me. Is this solution better than using
>"volatile bool x = true;"?
"Better" is not quite how I would characterize it. On systems where it
works, it's probably slower than using volatile and no locking. On the other
hand, it's a portable approach and is required on multiprocessor systems
with weakly ordered memory system. On such a system, if you declare x
volatile and use it outside mutex protection, and write to it in a given
thread, threads executing on other CPUs might not observe the write
immediately, and they might observe a series of writes including writes to x
in various orders, not necessarily the same order in which they were made.
If you're really on the ball, you might be able to issue your own memory
barriers and forgo the mutex, but it's a lot simpler just to use the mutex,
which also removes the atomicity issue for things more complex than simple
types like bool. BTW, atomic access to bool, int, etc. is an assumption,
which isn't guaranteed by the language standards, so that's another way in
which using a lock-free volatile approach such as the one I gave last time
can be dangerously non-portable. This is why I qualified that example with,
"On amenable hardware like x86, this idiom can work, ..." To that you can
add, "amenable types, and amenable access patterns". For example,
incrementing a variable is not atomic.
On Windows, using an event object is often superior to using any kind of
bool, because:
1. You needn't synchronize access to an event.
2. You can use an event in WaitForMultipleObjects and other wait functions,
which can make it much easier to implement an "end thread now" concept. It
can turn polling loops into infinite waits, which are more efficient and
less complex to write.
>"2. You need volatile to avoid undefined behavior in certain signal handler
>and setjmp/longjmp scenarios."
>
>Would you mind to give us some examples about this?
It's in the C Standard. Those things don't really come up in C++
programming, and IMO they're not worth committing to memory. IIRC, the
setjmp/longjmp usage concerns variables modified in the same function after
it calls setjmp, such that longjmp restores control to the point prior to
which those variables were modified. Or something like that. :)
>"3. You can use volatile, say, to declare a pointer to a volatile int, which
>represents a memory location updated at the interrupt level, something you
>can't synchronize with, and which is outside the compiler's knowledge of the
>program."
>
>This is totally beyond my apprehension. Would you please elaborate more on
>this point?
Again, you don't see this in ordinary Windows programming, because you don't
have low-level access to hardware. I expect it can come up if you're writing
device drivers, though. If you're talking about DOS, which has no memory
protection at all, I guess an example would be a TSR/application combo,
where the app periodically polls a memory location the TSR uses to
communicate with it. If the compiler can determine there's no way for the
app to modify the variable between successive reads, it can read it once and
propagate that value through those reads. Declaring the variable volatile
suppresses that optimization.
--
Doug Harrison
Microsoft MVP - Visual C++