3

Consider this function:

void foo(int * p)
{
   // something
}

Can the compiler assume that no other thread will modify the value pointed by p? Or does it have to act as if this value can be modified any moment?

void bar(volatile int * p)
{
}

If it does not, does the volatile keyword helps? GOTW #69 states that volatile keyword is mostly always ignored by compilers.

EDIT: Apparently there is some misunderstanding on the phrase “the compiler assumes”. Let me clarify this:

  • If the compiler assumes so, it can put the value of *p in a register the first time it is read, then use it until p goes out of scope. At that moment, it should write the value of *p at that memory address.
  • If the compiler does NOT assume so, every time *p is read, the compiler should fetch its value from memory as there is a chance some other thread modified it. Every time *p is changed, the compiler should write it to memory so that other threads can read it
qdii
  • 12,505
  • 10
  • 59
  • 116
  • 2
    Until recently the concept of a thread wasn't even built into the C++ language. The `volatile` keyword was mostly useful in a microcontroller context. – Mark Ransom Sep 10 '12 at 19:38
  • 2
    `volatile` simply tells the compiler to always dereference `p` to get the value from it. The memory model does not guarantee that while `bar()` accesses the memory no other thread will. So, there are no guarantees against data races. – Grim Fandango Sep 10 '12 at 20:02
  • Well, I would suggest clarifying it from the other direction: if it *does* assume so, what is the change in behavior that would entail? – GManNickG Sep 10 '12 at 20:03
  • @GrimFandango: No, it's the `int` that's volatile not `p`. Reads from (and writes to) `*p` cannot be optimized away but `p` can be dereferenced once (if it is not modified by the body of the function). – CB Bailey Sep 10 '12 at 20:18

5 Answers5

5

The compiler cannot make that assumption and neither can the programmer. The volatile keyword alone will not protect against concurrent access.

ryan0
  • 1,482
  • 16
  • 21
  • 3
    I would say the compiled *does* make that assumption, i.e. it acts as if there was no concurrent access. – juanchopanza Sep 10 '12 at 19:41
  • That’s what I think too, but there have been so many people stating the exact contrary that I can’t just give you the answer mark without more sources to back you up. – qdii Sep 10 '12 at 20:01
  • @juanchopanza Ah yes, i see your point. I was saying that the compiler would have no way of knowing, and thus could not act appropriately if a concurrent access attempt were to occur. Another way to say it would be "the compiler makes no assumptions about concurrent modification of *p; it just lets you do it." – ryan0 Sep 10 '12 at 20:09
  • Actually the word "assume" should not be used, because it seems to imply that the compiler will take special action based on some knowledge. A better question would be "does the compiler allow concurrent access to *p when volatile keyword is used?" That can only be interpreted one way. – ryan0 Sep 10 '12 at 20:15
  • I think the problem is with "can it assume". Of course it can, it is the compiler, it can do whatever it wants. But the assumption can be totally wrong :-) – juanchopanza Sep 10 '12 at 20:25
  • The compiler only does what the user tells it to do. If the user tells it to protect *p against concurrent access, it will. If the user doesn't tell it to do that, it won't. Only humans can assume things and it's generally a bad idea. – ryan0 Sep 10 '12 at 20:38
  • Looks like this has already been discussed ad nauseum here: http://stackoverflow.com/questions/2484980/why-is-volatile-not-considered-useful-in-multithreaded-c-or-c-programming – ryan0 Sep 10 '12 at 20:44
3

The compiler can, and does, assume that no other thread will modify the value pointed at by p, which means that you have to make sure that your code does not depend on this, or that it has appropriate synchronization mechanisms to avoid race conditions. In other words, the compiler makes the assumption, and that assumption can be wrong.

The volatile keyword has little relevance here.

juanchopanza
  • 223,364
  • 34
  • 402
  • 480
  • If I understand correctly, your first sentence says "the compiler assumes that no other thread will modify the value pointed by p". If the compiler assumes so, it should be able to put the value of `*p` in a register, and never fetch it back from memory again until `p` goes out of scope, doesn’t it? – qdii Sep 11 '12 at 13:48
  • @qdii the compiler acts as if there was no concurrent access. What ever it does at the level of hardware really depends on the hardware and the compiler. – juanchopanza Sep 11 '12 at 14:17
2

The rule is this: if one thread write to a data location at the same time that another thread reads from or writes to the same location the program has a data race and the behavior of the program is undefined. Reading between the lines, the compiler will assume that no other thread is writing to your data. It's your job to prevent data races. And, no, volatile doesn't affect that.

Pete Becker
  • 74,985
  • 8
  • 76
  • 165
  • Well, tetsuo000 says the exact contrary. Could you guys find reliable sources to back you up? – qdii Sep 10 '12 at 20:02
  • @qdii tetsuo000 is wrong, but I think it is just a misunderstanding in the wording. I would trust Pete Becker on this one! – juanchopanza Sep 10 '12 at 20:10
  • @qdii - it's not clear to me that tetsuo000 is saying the exact contrary. The problem is that the question is slightly ambiguous, and his answer is that "the compiler cannot make that assumption". It's not clear what "that assumption" is, which is why I didn't refer back to the words in the question, but I think we agree. The authority here is [intro.multithread], which is subclause 1.10 in the C++ standard. – Pete Becker Sep 11 '12 at 09:34
  • The problem is that i thought this was a question about concurrent programming; it's really about how the compiler behaves in the presence or lack of the "volatile" keyword. @qdii you should accept Pete Becker's answer. – ryan0 Sep 11 '12 at 23:16
1

If it does not, does the volatile keyword helps?

It is ignored by compiler (i.e. no optimization) and not the thread.

user1655481
  • 376
  • 1
  • 10
  • 1
    Sorry could you rephrase that? I don’t understand your answer. – qdii Sep 10 '12 at 19:50
  • 1
    I think he means that the compiler does no optimizations like store the contents of `p` in cache, but will always try to access the memory. But it does not say anything to any thread - it does not implicitly create some kind of a mutex. – Grim Fandango Sep 10 '12 at 19:57
1

Each thread gets its own copies of parameters representing the call that happened in that thread. The value of 'p' will only be shared if in fact they all point to the same thing. Assigning to 'p' in another thread will not effect 'p' in this thread as they are not even the same variable.

What 'p' points at is a totally different story. This is simply an area of memory. If other threads can access it then they can access it and they can write to it any time. The only way to protect something shared like this is with a mutex.

Edward Strange
  • 40,307
  • 7
  • 73
  • 125