How to Use C’s volatile Keyword

Posted on April 15, 2010. Filed under: C/C++ | Tags: , , , , |

by Nigel Jones

The proper use of C’s volatile keyword is poorly understood by many programmers. This is not surprising, as most C texts dismiss it in a sentence or two. This article will teach you the proper way to do it.

Have you experienced any of the following in your C or C++ embedded code?

  • Code that works fine–until you enable compiler optimizations
  • Code that works fine–until interrupts are enabled
  • Flaky hardware drivers
  • RTOS tasks that work fine in isolation–until some other task is spawned

If you answered yes to any of the above, it’s likely that you didn’t use the C keyword volatile. You aren’t alone. The use of volatile is poorly understood by many programmers. Unfortunately, most books about the C programming language dismiss volatile in a sentence or two.

C’s volatile keyword is a qualifier that is applied to a variable when it is declared. It tells the compiler that the value of the variable may change at any time–without any action being taken by the code the compiler finds nearby. The implications of this are quite serious. However, before we examine them, let’s take a look at the syntax.

volatile keyword syntax

To declare a variable volatile, include the keyword volatile before or after the data type in the variable definition. For instance both of these declarations will declare foo to be a volatile integer:

volatile int foo; 
int volatile foo;

Now, it turns out that pointers to volatile variables are very common, especially with memory-mapped I/O registers. Both of these declarations declare pReg to be a pointer to a volatile unsigned 8-bit integer:

volatile uint8_t * pReg; 
uint8_t volatile * pReg;

Volatile pointers to non-volatile data are very rare (I think I’ve used them once), but I’d better go ahead and give you the syntax:

int * volatile p;

And just for completeness, if you really must have a volatile pointer to a volatile variable, you’d write:

int volatile * volatile p;

Incidentally, for a great explanation of why you have a choice of where to place volatile and why you should place it after the data type (for example, int volatile * foo), read Dan Sak’s column “Top-Level cv-Qualifiers in Function Parameters” (Embedded Systems Programming, February 2000, p. 63).

Finally, if you apply volatile to a struct or union, the entire contents of the struct/union are volatile. If you don’t want this behavior, you can apply the volatile qualifier to the individual members of the struct/union.

Proper use of volatile

A variable should be declared volatile whenever its value could change unexpectedly. In practice, only three types of variables could change:

1. Memory-mapped peripheral registers

2. Global variables modified by an interrupt service routine

3. Global variables accessed by multiple tasks within a multi-threaded application

We’ll talk about each of these cases in the sections that follow.

Peripheral registers

Embedded systems contain real hardware, usually with sophisticated peripherals. These peripherals contain registers whose values may change asynchronously to the program flow. As a very simple example, consider an 8-bit status register that is memory mapped at address 0x1234. It is required that you poll the status register until it becomes non-zero. The naive and incorrect implementation is as follows:

uint8_t * pReg = (uint8_t *) 0x1234;

// Wait for register to become non-zero 
while (*pReg == 0) { } // Do something else

This will almost certainly fail as soon as you turn compiler optimization on, since the compiler will generate assembly language that looks something like this:

  mov ptr, #0x1234 mov a, @ptr

loop:
  bz loop

The rationale of the optimizer is quite simple: having already read the variable’s value into the accumulator (on the second line of assembly), there is no need to reread it, since the value will always be the same. Thus, in the third line, we end up with an infinite loop. To force the compiler to do what we want, we modify the declaration to:

uint8_t volatile * pReg = (uint8_t volatile *) 0x1234;

The assembly language now looks like this:

  mov ptr, #0x1234

loop:
  mov a, @ptr
  bz loop

The desired behavior is achieved.

Subtler problems tend to arise with registers that have special properties. For instance, a lot of peripherals contain registers that are cleared simply by reading them. Extra (or fewer) reads than you are intending can cause quite unexpected results in these cases.

Interrupt service routines

Interrupt service routines often set variables that are tested in mainline code. For example, a serial port interrupt may test each received character to see if it is an ETX character (presumably signifying the end of a message). If the character is an ETX, the ISR might set a global flag. An incorrect implementation of this might be:

int etx_rcvd = FALSE;

void main() 
{
    ... 
    while (!ext_rcvd) 
    {
        // Wait
    } 
    ...
}

interrupt void rx_isr(void) 
{
    ... 
    if (ETX == rx_char) 
    {
        etx_rcvd = TRUE;
    } 
    ...
}

With compiler optimization turned off, this code might work. However, any half decent optimizer will “break” the code. The problem is that the compiler has no idea that etx_rcvd can be changed within an ISR. As far as the compiler is concerned, the expression !ext_rcvd is always true, and, therefore, you can never exit the while loop. Consequently, all the code after the while loop may simply be removed by the optimizer. If you are lucky, your compiler will warn you about this. If you are unlucky (or you haven’t yet learned to take compiler warnings seriously), your code will fail miserably. Naturally, the blame will be placed on a “lousy optimizer.”

The solution is to declare the variable etx_rcvd to be volatile. Then all of your problems (well, some of them anyway) will disappear.

Multi-threaded applications

Despite the presence of queues, pipes, and other scheduler-aware communications mechanisms in real-time operating systems, it is still fairly common for two tasks to exchange information via a shared memory location (that is, a global). Even as you add a preemptive scheduler to your code, your compiler has no idea what a context switch is or when one might occur. Thus, another task modifying a shared global is conceptually identical to the problem of interrupt service routines discussed previously. So all shared global variables should be declared volatile. For example, this is asking for trouble:

int cntr;

void task1(void) 
{
    cntr = 0; 
    
    while (cntr == 0) 
    {
        sleep(1);
    } 
    ...
}

void task2(void) 
{
    ...
    cntr++; 
    sleep(10); 
    ...
}

This code will likely fail once the compiler’s optimizer is enabled. Declaring cntr to be volatile is the proper way to solve the problem.

Final thoughts

Some compilers allow you to implicitly declare all variables as volatile. Resist this temptation, since it is essentially a substitute for thought. It also leads to potentially less efficient code.

Also, resist the temptation to blame the optimizer or turn it off. Modern optimizers are so good that I cannot remember the last time I came across an optimization bug. In contrast, I come across failures by programmers to use volatile with depressing frequency.

If you are given a piece of flaky code to “fix,” perform a grep for volatile. If grep comes up empty, the examples given here are probably good places to start looking for problems.


This article was published in the July 2001 issue of Embedded Systems Programming. If you wish to cite the article in your own work, you may find the following MLA-style information helpful:

Jones, Nigel. “Introduction to the Volatile Keyword” Embedded Systems Programming, July 2001

Advertisements
Read Full Post | Make a Comment ( None so far )

Some multithreading tutorial URLs

Posted on June 6, 2007. Filed under: C/C++, Linux, Programming, Windows | Tags: , , , , , |

C

POSIX Threads Tutorial

http://math.arizona.edu/~swig/documentation/pthreads/

POSIX thread (pthread) libraries

http://www.yolinux.com/TUTORIALS/LinuxTutorialPosixThreads.html

C++

Multithreading Tutorial(Mutex, deadlock, livelock, scoped lock, Read/Write lock, Monitor Object, Active Object, boost) — Good!

http://www.paulbridger.com/multithreading_tutorial/

Multithreading Tutorial (mainly on Win32)

http://www.codeproject.com/KB/threads/MultithreadingTutorial.aspx

C++/CLI Threading

Part I:

http://www.drdobbs.com/windows/184402018

Part II:

http://www.drdobbs.com/windows/184402029

Threads in C++

http://www.linuxselfhelp.com/HOWTO/C++Programming-HOWTO-18.html

Read Full Post | Make a Comment ( None so far )

Slicing in C++

Posted on August 8, 2005. Filed under: C/C++ | Tags: , |

Suppose that class D is derived from class C. We can think of D as class C with some extra data and methods. In terms of data, D has all the data that C has, and possible more. In terms of methods, D cannot hide any methods of C, and may have additional methods. In terms of existing methods of C, the only thing that D can do is to override them with its own versions.

If x is an object of class D, then we can slice x with respect to C, by throwing away all of the extensions that made x a D, and keeping only the C part. The result of the slicing is always an object of class C.

Design Principle: Slicing an object with respect to a parent class C should still produce a well-formed object of class C.

Usage Warning: Even though D is-a C, you must be careful. If you have a argument type that is a C and you supply a D it will be sliced if you are doing call by value, pointer, or reference. See the example below.

Note on virtual functions. Their signatures are used to identify which one to execute.

Watch out for the sliced = operator, it can make the lhs inconsistent. Also, the operator= is never virtual, it wouldn’t make sense. For example, suppose classes A, B are both subclasses of class C. Just because an A is a C, and a B is a C, it doesn’t mean you can assign a B object to an A object. Without run-time type information you cannot make a safe assignment.

Usage Warning: If you ever change the size of an object, it and all its base classes must be recompiled! Unless everything is polymorphic and virtual!

13.2 slice.h

 

#ifndef _SLICE_
#define _SLICE_
 
#include <iostream.h>
 
class C {
 
public:
    explicit C(int initial = 0): id(initial), d1(100+initial) {}
    C(const C& arg): id(1000+arg.id), d1(arg.d1) {}
    virtual ~C()    {
        cout << "object " << id << " dying as a C\n";
    }
 
 
    void operator=(const C& rhs) 
    {
        cout << "Object " << id << " doing C =\n";
        Assign(rhs); 
    }
 
    virtual void Assign(const C& rhs) 
    {
        cout << "Assign C\n";
        d1 = rhs.d1;
    }
 
    void Ident() 
    {
        cout << "Object " << id 
            << " thinks it is a C object, d1="
            << d1 << "\n";
    }
 
    virtual void VirtIdent() 
    {
        cout << "Object " << id << 
            " virtually thinks it is a C object, d1="
            << d1 << "\n";
    }
 
protected:
    int id;
    int d1;
};
 
class D: public C {
public:
 
    explicit D(int initial = 0): C(initial), d2(200+initial) {}
    D(const D& arg): C(arg.id), d2(arg.d2) {}
    ~D() 
    {
        cout << "object " << id << " dying as a D\n";
    }
 
    void operator=(const D& rhs) 
    {
        cout << "Object " << id << " doing D =\n";
        Assign(rhs);
    }
 
    void Assign(const D& rhs)
    {
        cout << "Assign in D\n";
        C::Assign(rhs);
        d2 = rhs.d2;
    }
 
    // This version of Ident overrides the parent's, 
    // if we are not sliced!
    void Ident() 
    {
        cout << "Object " << id << 
            " thinks it is a D object, d1=" 
            << d1 << " d2=" << d2 << "\n";
    }
 
    void VirtIdent() 
    {
        cout << "Object " << id << 
            " virtually thinks it is a D object, d1=" 
            << d1 << " d2=" << d2 << "\n";
    }
private:
    int d2;
};
#endi

 

13.3 demo.cpp

 

#include <iostream.h>
#include "slice.h"
 
void SliceIt1(C arg) {
    cout << "Inside SliceIt1: ";
    arg.Ident();
    arg.VirtIdent();
}
 
void SliceIt2(C* arg) {
    cout << "Inside SliceIt2: ";
    (*arg).Ident();
    (*arg).VirtIdent();
}
 
void SliceIt3(C& arg) {
    cout << "Inside SliceIt3: ";
    arg.Ident();
    arg.VirtIdent();
}
 
void CopyIt1(C& x, C& y) {
    cout << "Inside CopyIt1:\n";
    x.Ident(); x.VirtIdent();
    y.Ident(); y.VirtIdent();
    x = y;
    x.Ident(); x.VirtIdent();
}
 
int main(int argc, char* argv[])
{
    D x(1);
    C y(2);
    D z(3);
 
    x.Ident(); x.VirtIdent();
    y.Ident(); y.VirtIdent();
    z.Ident(); z.VirtIdent();
    cout << "\n";
 
    SliceIt1(x); 
    SliceIt1(y);
    cout << "\n";
 
    SliceIt2(&x);
    SliceIt2(&y);
    cout << "\n";
 
    SliceIt3(x);
    SliceIt3(y);
    cout << "\n";
 
    CopyIt1(x, y);  
    // state of x wrong now
    x.VirtIdent();
    x.Ident();
    cout << "\n";
 
    CopyIt1(x, z);
    z.VirtIdent();
    z.Ident();
    cout << "\n";
    return 0;
}

 

13.4 output.txt

 

Object 1 thinks it is a D object, d1=101 d2=201
Object 1 virtually thinks it is a D object, d1=101 d2=201
Object 2 thinks it is a C object, d1=102
Object 2 virtually thinks it is a C object, d1=102
Object 3 thinks it is a D object, d1=103 d2=203
Object 3 virtually thinks it is a D object, d1=103 d2=203
 
Inside SliceIt1: Object 1001 thinks it is a C object, d1=101
Object 1001 virtually thinks it is a C object, d1=101
object 1001 dying as a C
Inside SliceIt1: Object 1002 thinks it is a C object, d1=102
Object 1002 virtually thinks it is a C object, d1=102
object 1002 dying as a C
 
Inside SliceIt2: Object 1 thinks it is a C object, d1=101
Object 1 virtually thinks it is a D object, d1=101 d2=201
Inside SliceIt2: Object 2 thinks it is a C object, d1=102
Object 2 virtually thinks it is a C object, d1=102
 
Inside SliceIt3: Object 1 thinks it is a C object, d1=101
Object 1 virtually thinks it is a D object, d1=101 d2=201
Inside SliceIt3: Object 2 thinks it is a C object, d1=102
Object 2 virtually thinks it is a C object, d1=102
 
Inside CopyIt1:
Object 1 thinks it is a C object, d1=101
Object 1 virtually thinks it is a D object, d1=101 d2=201
Object 2 thinks it is a C object, d1=102
Object 2 virtually thinks it is a C object, d1=102
Object 1 doing C =
Assign C
Object 1 thinks it is a C object, d1=102
Object 1 virtually thinks it is a D object, d1=102 d2=201
Object 1 virtually thinks it is a D object, d1=102 d2=201
Object 1 thinks it is a D object, d1=102 d2=201
 
Inside CopyIt1:
Object 1 thinks it is a C object, d1=102
Object 1 virtually thinks it is a D object, d1=102 d2=201
Object 3 thinks it is a C object, d1=103
Object 3 virtually thinks it is a D object, d1=103 d2=203
Object 1 doing C =
Assign C
Object 1 thinks it is a C object, d1=103
Object 1 virtually thinks it is a D object, d1=103 d2=201
Object 3 virtually thinks it is a D object, d1=103 d2=203
Object 3 thinks it is a D object, d1=103 d2=203
 
object 3 dying as a D
object 3 dying as a C
object 2 dying as a C
object 1 dying as a D
object 1 dying as a C

}

Here is another example:

 
class Shape {
public:
	Shape() { };
	virtual void draw() {};
};

class Circle : public Shape {
private:
	int m_iRadius;
public:
	Circle(int iRadius){ m_iRadius = iRadius; }
	virtual void draw() { /*do drawing*/}
	int GetRadius(){ return m_iRadius; }
};

void funcx(Shape shape) { /*do something*/}

Now, what if we try this:

 
Circle circle(2);
funcx(circle); //Pass a Circle as parameter, when function expects a Shape

Will this result in an error? No. Because Circle is derived from Shape, the compiler will generate a default assignment operator and will copy all the fields common to Circle and Shape. But the m_iRadius field will be lost and there is no way it can be used in funcx.

Another problem is the loss of type information. This may result in undesirable behavior by virtual functions. This phenomenon is called slicing. It is common in exception handling, when exceptions are caught using base class. It is used either to avoid multiple catch blocks or when the types of possible thrown exception is unknown.

 
class CException {};
class CMemoryException : public CException {};
class CFileException: public CException{};

try{ /*do something silly*/ }
catch(CException exception) {/*handle exception*/}

To avoid slicing, change the operations so they use pointer or reference to the base class object rather then the base class object itself. In the given sample code, funcx can be changed so that it takes a pointer/reference to Shape as a parameter rather than Shape:

 
void funcx(Shape *shape) { /*do something*/}

Inside the function body, this pointer can be safely type-casted to a Circle pointer to access Circle specific information:

 
dynamic_cast(shape)->GetRadius();

Reference:
http://webdocs.cs.ualberta.ca/~hoover/Courses/201/201-New-Notes/lectures/section/slice.htm
http://www.devx.com/tips/Tip/14570
Read Full Post | Make a Comment ( None so far )

The “Clockwise/Spiral Rule” of C declaration

Posted on January 9, 2005. Filed under: C/C++ | Tags: , , , , |

The “Clockwise/Spiral Rule”

By David Anderson

There is a technique known as the “Clockwise/Spiral Rule” which enables any C programmer to parse in their head any C declaration!

There are three simple steps to follow:

  1. Starting with the unknown element, move in a spiral/clockwise direction; when ecountering the following elements replace them with the corresponding english statements: 
    [X] or []
    => Array X size of… or Array undefined size of…
    (type1, type2)
    => function passing type1 and type2 returning…
    *
    => pointer(s) to…

     

  2. Keep doing this in a spiral/clockwise direction until all tokens have been covered. 
  3. Always resolve anything in parenthesis first!

Example #1: Simple declaration

                     +-------+
                     | +-+   |
                     | ^ |   |
                char *str[10];
                 ^   ^   |   |
                 |   +---+   |
                 +-----------+

Question we ask ourselves: What is str?

“str is an…

  • We move in a spiral clockwise direction starting with `str’ and the first character we see is a `[‘ so, that means we have an array, so…

    “str is an array 10 of…

  • Continue in a spiral clockwise direction, and the next thing we encounter is the `*’ so, that means we have pointers, so…

    “str is an array 10 of pointers to…

  • Continue in a spiral direction and we see the end of the line (the `;’), so keep going and we get to the type `char’, so…

    “str is an array 10 of pointers to char”

  • We have now “visited” every token; therefore we are done!

Example #2: Pointer to Function declaration

                     +--------------------+
                     | +---+              |
                     | |+-+|              |
                     | |^ ||              |
                char *(*fp)( int, float *);
                 ^   ^ ^  ||              |
                 |   | +--+|              |
                 |   +-----+              |
                 +------------------------+

Question we ask ourselves: What is fp?

“fp is a…

  • Moving in a spiral clockwise direction, the first thing we see is a `)’; therefore, fp is inside parenthesis, so we continue the spiral inside the parenthesis and the next character seen is the `*’, so…

    “fp is a pointer to…

  • We are now out of the parenthesis and continuing in a spiral clockwise direction, we see the `(‘; therefore, we have a function, so…

    “fp is a pointer to a function passing an int and a pointer to float returning…

  • Continuing in a spiral fashion, we then see the `*’ character, so…

    “fp is a pointer to a function passing an int and a pointer to float returning a pointer to…

  • Continuing in a spiral fashion we see the `;’, but we haven’t visited all tokens, so we continue and finally get to the type `char’, so…

    “fp is a pointer to a function passing an int and a pointer to float returning a pointer to a char”

Example #3: The “Ultimate”

                      +-----------------------------+
                      |                  +---+      |
                      |  +---+           |+-+|      |
                      |  ^   |           |^ ||      |
                void (*signal(int, void (*fp)(int)))(int);
                 ^    ^      |      ^    ^  ||      |
                 |    +------+      |    +--+|      |
                 |                  +--------+      |
                 +----------------------------------+

Question we ask ourselves: What is `signal’?

Notice that signal is inside parenthesis, so we must resolve this first!

  • Moving in a clockwise direction we see `(‘ so we have…

    “signal is a function passing an int and a…

  • Hmmm, we can use this same rule on `fp’, so… What is fp? fp is also inside parenthesis so continuing we see an `*’, so…

    fp is a pointer to…

  • Continue in a spiral clockwise direction and we get to `(‘, so…

    “fp is a pointer to a function passing int returning…”

  • Now we continue out of the function parenthesis and we see void, so…

    “fp is a pointer to a function passing int returning nothing (void)”

  • We have finished with fp so let’s catch up with `signal’, we now have…

    “signal is a function passing an int and a pointer to a function passing an int returning nothing (void) returning…

  • We are still inside parenthesis so the next character seen is a `*’, so…

    “signal is a function passing an int and a pointer to a function passing an int returning nothing (void) returning a pointer to…

  • We have now resolved the items within parenthesis, so continuing clockwise, we then see another `(‘, so…

    “signal is a function passing an int and a pointer to a function passing an int returning nothing (void) returning a pointer to a function passing an int returning…

  • Finally we continue and the only thing left is the word `void’, so the final complete definition for signal is:

    “signal is a function passing an int and a pointer to a function passing an int returning nothing (void) returning a pointer to a function passing an int returning nothing (void)”

The same rule is applied for const and volatile. For Example:

	const char *chptr;
  • Now, what is chptr??

    “chptr is a pointer to a char constant”

How about this one:

	char * const chptr;
  • Now, what is chptr??

    “chptr is a constant pointer to char”

Finally:

	volatile char * const chptr;
  • Now, what is chptr??

    “chptr is a constant pointer to a char volatile.”

Practice this rule with the examples found in K&R II on page 122.

Reference:

http://c-faq.com/decl/spiral.anderson.html

Read Full Post | Make a Comment ( None so far )

Liked it here?
Why not try sites on the blogroll...