Is volatile int in C as good as std::atomic o

2020-02-08 14:50发布

问题:

I need to have atomic variables in my program. Previously I was using std::atomic<int>, but the platform in which I'm working now does not have a g++ compiler that supports C++0x. I used volatile int and it seems to be working, as I haven't experienced a race condition yet in the multicore system I'm testing it on.

My question is if volatile int is atomic like std::atomic<int>? Also, does it creates memory barriers (which I also require)?

回答1:

I've seen you asking about GCC in some comments, here you go.

GCC's Built-in functions for atomic memory access



回答2:

No. volatile has nothing to do with multithreading. It doesn't enforce a memory barrier (although some compilers might choose to add that anyway), and it makes no guarantees about read/write reordering with respect to non-volatile objects.

volatile was added to support writing to memory-mapped hardware I/O registers, and such cases, where it is important that your write isn't optimized away, but no precise ordering guarantees wrt. non-volatile reads/wrties are required.

You might also want to read this



回答3:

Volatile variables do NOT imply memory barriers, and do not have the exchange or compare_exchange_* operations of std::atomic. They do avoid the compiler lifting a load into multiple loads on the machine code level (and vice versa, and similar for stores) but that's it.

You may be interested in these articles:

  • volatile considered harmful
  • Volatile: Almost Useless for Multi-Threaded Programming

If you do not have std::atomic, you may want to use boost::atomic, or use the low-level barrier and atomic-operation primitives offered by whatever compiler you're using.



回答4:

Before C++0x, the language wasn't thread aware, so it did not prevent multiple access. Declaring it volatile will help some, but it won't prevent races.

See http://en.wikipedia.org/wiki/Volatile_variable for more details.

To truly make operations atomic, you'll need to employ whatever locking mechanism your threading library (win32 threads, pthreads, etc) provides.



回答5:

There's a good summary of the diffs here, from Herb Sutter. In summary (cut and paste):

To safely write lock-free code that communicates between threads without using locks, prefer to use ordered atomic variables: Java/.NET volatile, C++0x atomic, and C-compatible atomic_T.

To safely communicate with special hardware or other memory that has unusual semantics, use unoptimizable variables: ISO C/C++ volatile. Remember that reads and writes of these variables are not necessarily atomic, however.



回答6:

volatile basically tells the compiler it can't make assumptions about what is in a particular memory location. For instance

bool test = true;
while(!test)
{
    /* do something (e.g. wait) */
}

the compiler might optimize away the whole while because it assumes test is always true. If however test is at some point going to be updated from elsewhere (some hardware or another thread for instance) the we do not want the compiler to assume it knows what is in test. We can tell the compiler that using volatile.

As the other answers say, it gives no guarantees about what order things access the memory location in.

P.s. I shamelessly stole that example from somewhere but can't remember where I saw it.