Is volatile int in C as good as std::atomic<int> of C++0x?
Asked Answered
P

6

19

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)?

Peculate answered 8/7, 2011 at 16:37 Comment(3)
If it was, why would they have added atomic<> at all? ;) The usual rule of thumb applies, that the language designers aren't completely insane, so there's probably some reason for what they do :)Frobisher
So what is the solution? Any idea?Peculate
The "solution"? You asked what's basically a yes/no question. The answer is "no" (and the reasoning is, as I said, "if they did do the same thing, there'd have been no reason to add atomic). But there is no problem statement in your question, and so there is no room for a "solution". Are you looking for something like "no, volatile isn't suitable here, so you need to either use std::atomic, or use a proper memory barrier"? If so, then that's your answer. :)Frobisher
E
4

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

GCC's Built-in functions for atomic memory access

Elayneelazaro answered 8/7, 2011 at 17:35 Comment(0)
F
28

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

Frobisher answered 8/7, 2011 at 16:41 Comment(10)
Does std::atomic impose ordering requirements on non-atomic accesses?Fossick
A volatile variable's value can change without the program's consent, so the compiler should not use it in optimization strategies.Unconscionable
yes. atomic implies/requires that the operation is done in an atomic fashion (i.e. all at once). Volatile simply tells the compiler that it cannot cache the variable or make assumptions about it's valueBermejo
@Ben: yeah, as far as I know, it is surrounded by memory barriers, essentiallyFrobisher
@jalf: Since writing to a volatile is "observable", wouldn't it give you some ordering protection? That is, if I wrote to volatile1 using an expression that - perhaps - has side effects, then wrote to volatile2, I would think the "observable" behavior guarantee would grant the order.Viosterol
@John: Writes to a volatile object are observable, so you do have a guarantee that volatile writes won't be reordered. But all the non-volatile reads/writes that go in between aren't observable, and so they can be reordered freely, as long as the observable behavior is preserved.Frobisher
Note that for MSVC volatile does imply a memory barrier, and there's no way of opting out of this behavior.Mixture
+1 for the link to Volatile: Almost Useless for Multi-Threaded ProgrammingPatton
Interesting paper to find on a Intel site - because it is wrong in so many aspects :-) While I agree that there is almost no portable use of volatile, it is actually very useful on non portable code (like the core of every threading libray). Intel does make some guarantees to atomicity and memory ordering which happen to be very useful in conjunction with volatile.Butterflies
So given that the article talks about C++ (implicitly portable standard C++), what is it wrong about? The article never claimed that volatile wasn't useful in non-portable code. It talked about C++, and the guarantees offered by C++Frobisher
J
6

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:

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.

Jeanelle answered 8/7, 2011 at 16:41 Comment(3)
Any equivalent of std::atomic<int> in gcc?Peculate
You could try this: gcc.gnu.org/onlinedocs/gcc-4.1.2/gcc/Atomic-Builtins.html, se also #166431Elidiaelie
@MetallicPriest: GCC since 4.4 is supposed to have it.Brott
E
4

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

GCC's Built-in functions for atomic memory access

Elayneelazaro answered 8/7, 2011 at 17:35 Comment(0)
W
2

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.

Works answered 8/7, 2011 at 16:47 Comment(1)
I realized I completely messed up that example, I hope the function of volatile still makes sense from what I said. I'll try and hunt down the original source of the example and post it here.Works
P
1

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.

Present answered 8/7, 2011 at 16:40 Comment(0)
E
1

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.

Elidiaelie answered 8/7, 2011 at 16:44 Comment(6)
Which header file to include when using atomic_t?Peculate
@MetallicPriest: there is no atomic_t in GCC. It's a VC++ extension.Corrode
@Steve, @MetallicPriest: excuse me, I was looking for an actual atomic_t keyword. GCC has atomic types in <stdatomic.h> (C) or <cstdatomic> (C++).Corrode
An _Atomic qualifier is proposed for C1x. I don't think anyone supports it yet though. The C++0x and the C1y did work together on atomics and the thread model so they maximized compatibility.Airspeed
In some gcc version stdatomic.h is not present.Peculate
Yes, this stuff is patchy hence the drive to standardize.Elidiaelie

© 2022 - 2024 — McMap. All rights reserved.