Search code examples
c++multithreadingvolatile

Portable thread class implemented in C++


When writing C programs that need to share a file scope variable between the application and an interrupt routine/a thread/a callback routine, it is well-known that the variable must be declared volatile, or else the compiler may do incorrect optimizations. This is an example of what I mean:

int flag;

void some_interrupt (void)
{
  flag = 1;
}



int main()
{
  flag = 0;
  ...

  /* <-- interrupt occurs here */

  x = flag; /* BUG: the compiler doesn't realize that "flag" was changed 
                    and sets x to 0 even though flag==1 */

}

To prevent the above bug, "flag" should have been declared as volatile.

My question is: how does this apply to C++ when creating a class containing a thread?

I have a class looking something like this:

class My_thread
{
  private:
    int flag;

    static void thread_func (void* some_arg) // thread callback function
    {
      My_thread* this_ptr= (My_thread*)some_arg;

    }
};

"some_arg" will contain a pointer to an instance of the class, so that each object of "My_thread" has its own thread. Through this pointer it will access member variables.

Does this mean that "this_ptr" must be declared as pointer-to-volatile data? Must "flag" be volatile as well? And if so, must I make all member functions that modify "flag" volatile?

I'm not interested in how a particular OS or compiler behaves, I am looking for a generic, completely portable solution.

EDIT: This question has nothing to do with thread-safety whatsoever!

The real code will have semaphores etc.

To clarify, I wish to avoid bugs caused by the compiler's unawareness of that a callback function may be called from sources outside the program itself, and therefore make incorrect conclusions about whether certain variables have been used or not. I know how to do this in C, as illustrated with the first example, but not in C++.


Solution

  • Well, that edit makes all the difference of the world. Semaphores introduce memory barriers. Those make volatile redundant. The compiler will always reload int flag after any operation on a semaphore.

    Fred Larson already predicted this. volatile is insufficient in the absence of locks, and redudant in the presence of locks. That makes it useless for thread-safe programming.