reg%lti.UUCP@bu-it.bu.edu (Rick Genter x18) (06/03/88)
If anyone still (!) doesn't understand why volatile is necessary,
look at the March, 1988 issue of the Microsoft Systems Journal,
page 23, which contains a listing of a sample program that uses
multiple threads of execution within a single process. There is
a boolean variable called bContinueCalc which gets set to FALSE
when the calculation loop is supposed to abort. The calculation
loop is
for (A = 1.0, i = 0 ; i < iCalcRep ; i++) {
if (! bContinueCalc)
break;
A = Savage (A);
}
The other thread of execution deals with the user interface (the
Presentation Manager in OS/2). If the ABORT button is clicked on,
the variable bContinueCalc is set to FALSE. bContinueCalc is a
global variable declared as
BOOL bContinueCalc = FALSE;
It should be declared
volatile BOOL bContinueCalc = FALSE;
otherwise the C compiler is perfectly justified taking the test of
bContinueCalc out of the for loop, thus invalidating the whole use
of the variable.
- reg
(P.S. Don't flame me about the naming conventions, OS/2, etc. I'm
just citing an example; I don't claim to *like* any of what I cited.)
--
Rick Genter ...!buita!lti!reg
Language Technology, Inc. reg%lti.uucp@bu-it.bu.edu
27 Congress St., Salem, MA 01970 (617) 741-1507
faustus@ic.Berkeley.EDU (Wayne A. Christopher) (06/03/88)
In article <15735@brl-adm.ARPA>, reg%lti.UUCP@bu-it.bu.edu (Rick Genter x18) writes: > for (A = 1.0, i = 0 ; i < iCalcRep ; i++) { > if (! bContinueCalc) > break; > A = Savage (A); > } > ... should be declared > > volatile BOOL bContinueCalc = FALSE; > > otherwise the C compiler is perfectly justified taking the test of > bContinueCalc out of the for loop, thus invalidating the whole use > of the variable. I don't think this is right. If bContinueCalc were an automatic variable that never had its address taken, or there were no function call inside the loop, then the test could be taken out, but not otherwise. "volatile" doesn't mean that more than one function can modify a variable, but that a variable can become modified by an event that happens wholly outside of the control of the program. These are limited to (I think) signal handlers and device registers. If your program doesn't use either of these, you don't have to declare anything volatile. Wayne
tim@amdcad.AMD.COM (Tim Olson) (06/03/88)
In article <3754@pasteur.Berkeley.Edu> faustus@ic.Berkeley.EDU (Wayne A. Christopher) writes: | In article <15735@brl-adm.ARPA>, reg%lti.UUCP@bu-it.bu.edu (Rick Genter x18) writes: | > for (A = 1.0, i = 0 ; i < iCalcRep ; i++) { | > if (! bContinueCalc) | > break; | > A = Savage (A); | > } | > ... should be declared | > | > volatile BOOL bContinueCalc = FALSE; | > | > otherwise the C compiler is perfectly justified taking the test of | > bContinueCalc out of the for loop, thus invalidating the whole use | > of the variable. Actually, because there is a function call in the loop, the test cannot typically be removed, unless the compiler can trace the program flow and ensure that bContinueCalc is not modified elsewhere. However, if there were no function call in the loop, then the compiler *is* justified in moving the test out of the loop, since it is invariant. Here is an example, from the MetaWare 29000 C compiler: === non-volatile, function call in loop === ;int bool; ; ;int f() ;{ ; int i = 0; ; ; for (;;) { ; if (bool) ; break; ; i = A(i); ; } ; return i; ;} const gr96,0 ; (0x0) const lr4,_bool consth lr4,_bool L00012: load 0,0,gr121,lr4 <-- note that load of "bool", cpeq gr121,gr121,0 <-- and comparison are in the loop jmpt gr121,L00014 nop . . === non-volatile, no function call in loop === ;int bool; ; ;int f() ;{ ; int i = 0; ; ; for (;;) { ; if (bool) ; break; ; ++i; ; } ; return i; ;} const gr121,_bool consth gr121,_bool load 0,0,gr121,gr121 <-- "bool" is loop-invariant, so it const gr96,0 ; (0x0) <-- is moved out, along with the cpeq gr121,gr121,0 <-- comparison to zero! L00012: jmpt gr121,L00014 nop jmpi lr0 nop L00014: jmp L00012 add gr96,gr96,1 === volatile, no function call in loop === ;volatile int bool; ; ;int f() ;{ ; int i = 0; ; ; for (;;) { ; if (bool) ; break; ; ++i; ; } ; return i; ;} const gr96,0 ; (0x0) const gr120,_bool consth gr120,_bool L00012: load 0,0,gr121,gr120 <-- load is not hoisted because cpeq gr121,gr121,0 <-- of volatile declaration. jmpt gr121,L00014 nop jmpi lr0 nop L00014: jmp L00012 add gr96,gr96,1 -- Tim Olson Advanced Micro Devices (tim@delirun.amd.com)
bill@proxftl.UUCP (T. William Wells) (06/18/88)
In article <3754@pasteur.Berkeley.Edu>, faustus@ic.Berkeley.EDU (Wayne A. Christopher) writes: ) In article <15735@brl-adm.ARPA>, reg%lti.UUCP@bu-it.bu.edu (Rick Genter x18) writes: ) > for (A = 1.0, i = 0 ; i < iCalcRep ; i++) { ) > if (! bContinueCalc) ) > break; ) > A = Savage (A); ) > } ) > ... should be declared ) > ) > volatile BOOL bContinueCalc = FALSE; ) > ) > otherwise the C compiler is perfectly justified taking the test of ) > bContinueCalc out of the for loop, thus invalidating the whole use ) > of the variable. ) ) I don't think this is right. If bContinueCalc were an automatic variable ) that never had its address taken, or there were no function call inside the ) loop, then the test could be taken out, but not otherwise. "volatile" ) doesn't mean that more than one function can modify a variable, but that ) a variable can become modified by an event that happens wholly outside of ) the control of the program. Not quite, a nonvolatile variable is presumed to be modified only by execution in the standard C paradigm. This implies single thread execution, among other things. Now, if bContinueCalc is demonstrably not changed in Savage(), the compiler is justified in moving the test outside the loop. To prevent that, one should declare it volatile, meaning that something outside the normal flow of execution can change it.