Proper Use of Volatile?

B

bwaichu

Can someone help me out here? This is one of those areas of C
that I am fuzzy on. I'm not quite sure when I should use volatile.

If you could provide an example, that would help out a lot.

I know it has to do with the expectation that the variable can be
changed outside of the control of the program. I know it has to
do with telling the compiler to not optimize that piece of code,
so that the variable can be changed from outside of the program.

But I struggle with the thought process as to deciding when to
use it.

<OT>
I was reading the source code for ftp (the client), and I
see it used throughout. And I found myself second guessing
my understanding of its use.
</OT>

Thanks!
 
E

Eric Sosman

Can someone help me out here? This is one of those areas of C
that I am fuzzy on. I'm not quite sure when I should use volatile.

If you could provide an example, that would help out a lot.

I know it has to do with the expectation that the variable can be
changed outside of the control of the program. I know it has to
do with telling the compiler to not optimize that piece of code,
so that the variable can be changed from outside of the program.

Specifically, it tells the compiler that the very act of
accessing the volatile variable, for read or for write, may have
a necessary side-effect. The compiled code must actually perform
all the accesses implied by the abstract machine, and cannot
optimize them away or rearrange them w.r.t. sequence points.
A loop that polls a volatile device register until the READY bit
is set must actually read the register on each iteration; the
compiler cannot just fetch it once and then go into a tight loop
testing and re-testing the fetched value. A sequence of
assignments like

*device_register = DEVICE_RESET;
*device_register = DEVICE_SETMODE | 42;
*device_register = DEVICE_START;

cannot be replaced by the final assignment alone.

Unfortunately, there remains one gigantic non-portable hole in
the semantics of volatile: The compiled code must perform all the
accesses implied by the abstract machine, but the implementation
gets to define what an "access" is. Many uses of volatile thus
require intimacy with the implementation's documentation.
But I struggle with the thought process as to deciding when to
use it.

A strictly-conforming C program needs volatile in only one
circumstance (unless I've forgotten something ;-): when a function
that calls setjmp() wants to rely on the value of a local variable
that might be changed between setjmp() and longjmp(). Makeing such
a variable volatile "forces it to memory" whenever it's changed, and
forces it to be read from memory whenever it's inspected. Thus you
never get a value in a register becoming out-of-date with respect
to the value in memory when longjmp() messes up the normal flow
of control.

Other uses of volatile are connected with implementation-
specific goodies like asynchronous signals, memory locations that
do something other than passively store values (e.g., hardware
counters, I/O status and command registers), and other sorts of
"independent activity." (Not including multi-threaded programs,
by the way: volatile is neither necessary nor sufficient for data
that's shared between threads.)

If you're not using setjmp()/longjmp() and you're not using
asynchronous signals and special memory locations and the like,
you don't need (or want) volatile.
<OT>
I was reading the source code for ftp (the client), and I
see it used throughout. And I found myself second guessing
my understanding of its use.
</OT>

Keep in mind that the author of the code may have been as
uncertain about volatile as you are. Just because something has
been ritten doesn't mene its rite.
 
T

Thad Smith

Can someone help me out here? This is one of those areas of C
that I am fuzzy on. I'm not quite sure when I should use volatile.

If you could provide an example, that would help out a lot.

Volatile is often used when a variable is written in an interrupt
routine and read by a background routine. Or it may be written by one
thread of execution and read by another. Another use is for
memory-mapped I/O ports, instead of memory, such that reading at a
particular address queries the current state of hardware and writing to
the address may send control signals to external hardware.

All of these examples violate the normal execution model in which a
value, once written, does not change until explicitly written again by
the normal program control.

Multiple threads and interrupts are outside the scope of Standard C, but
are commonly used with C. Volatile improves the utility of C in these
non-strictly-conforming usages.
 
K

Kenneth Brody

Can someone help me out here? This is one of those areas of C
that I am fuzzy on. I'm not quite sure when I should use volatile.

If you could provide an example, that would help out a lot.

I know it has to do with the expectation that the variable can be
changed outside of the control of the program. I know it has to
do with telling the compiler to not optimize that piece of code,
so that the variable can be changed from outside of the program.

But I struggle with the thought process as to deciding when to
use it.

NB: Both memory-mapped I/O and threads are beyond the scope of
clc, and the following examples which use busy-loops aren't
necessarily good coding practice, but I believe they show
some uses of volatile in an easy-to-understand method.

Consider memory-mapped I/O, such as a status register on an output
port:

extern char volatile StatusRegister;
#define STATUS_BUSY 0x01
extern char OutputPort;

void SendString(char *pt)
{
for ( ; *pt ; pt++ )
{
while ( StatusRegister & STATUS_BUSY )
;
OutputPort = *pt;
}
}

If StatusRegister weren't "volatile", then the compiler could
optimize the while loop to read it only once, and then either
exit the loop immediately, or turn it into an infinite loop.

Another situation is multiple threads. Following the example
above, you may have a loop that checks the status of the other
thread via a volatile variable. If the compiler can determine
that your loop cannot change the variable, then once again it
can be optimized to reading it only once, and your code will
never see the change.

Basically, "volatile" tells the compiler "don't assume that the
value of the variable hasn't changed, just because I haven't
changed it".
<OT>
I was reading the source code for ftp (the client), and I
see it used throughout. And I found myself second guessing
my understanding of its use.
</OT>

Well, as someone else pointed out, it may be that the person
who wrote the code you were examining didn't understand volatile,
either.

On the other hand, it's possible that the program you were
looking at use another thread to do the transfers, and the main
thread examines the volatile variable to get information about
the transfer.

--
+-------------------------+--------------------+-----------------------+
| Kenneth J. Brody | www.hvcomputer.com | #include |
| kenbrody/at\spamcop.net | www.fptech.com | <std_disclaimer.h> |
+-------------------------+--------------------+-----------------------+
Don't e-mail me at: <mailto:[email protected]>
 
F

Flash Gordon

Eric said:
(e-mail address removed) wrote:


A strictly-conforming C program needs volatile in only one
circumstance (unless I've forgotten something ;-): when a function
that calls setjmp() wants to rely on the value of a local variable
that might be changed between setjmp() and longjmp(). Makeing such

<snip>

How about:
volatile sig_atomic_t flag;
So that a signal handler for one of the few signals that the C standard
defines can safely set or test the flag?
 
E

Eric Sosman

Flash said:
<snip>

How about:
volatile sig_atomic_t flag;
So that a signal handler for one of the few signals that the C standard
defines can safely set or test the flag?

It's not necessary for synchronous signals, and as far as
I can tell asynchronous signals are outside the bounds of
strict conformance; that's why I mentioned them among the
"implementation-specific goodies."
 
F

Flash Gordon

Eric said:
It's not necessary for synchronous signals, and as far as
I can tell asynchronous signals are outside the bounds of
strict conformance; that's why I mentioned them among the
"implementation-specific goodies."

I see no guarantee in the standard that any given signal will *not* be
raised by an asynchronous mechanism, such as the Unix kill command. So I
believe that this is strictly conforming (modulo trypographical errors):

#include <signal.h>
#include <stdio.h>

volatile sig_atomic_t flag;

void sig(int i)
{
flag = 1;
}

int main(void)
{
char buf[2];
signal(SIGINT,sig);
fgets(stdin, buf, sizeof buf);
return 0;
}

Since although flag can possibly be caused to be set in some
implementation defined defined manner no output actually depends on
whether this occurs or not. However, if you drop the volatile and some
implementation defined mechanism (e.g. the user pressing ctrl+C) is used
to cause a SIGINT to be raised then undefined behaviour is invoked
potentially affecting the output of the program, thus causing it to no
longer be strictly conforming.

Of course, I am stretching a bit here, but I would be interested from an
academic perspective in the opinions of others on this ;-)

The truth is I just never thought about volatile not being required if
the signal handler was only ever invoked through the use of the raise
function :)
 

Ask a Question

Want to reply to this thread or ask your own question?

You'll need to choose a username for the site, which only take a couple of moments. After that, you can post your question and our members will help you out.

Ask a Question

Similar Threads


Members online

No members online now.

Forum statistics

Threads
473,755
Messages
2,569,537
Members
45,022
Latest member
MaybelleMa

Latest Threads

Top