Thread: Question about volatile

  1. #1
    Registered User
    Join Date
    Nov 2008
    Posts
    127

    Question about volatile

    I'm trying to figure out if I need to use volatile or not. All of the examples I've seen so far seem to be set up as some small loop is checking the state of a variable to see if it should exit the loop but that variable is only changed from some other thread (not inside the loop).

    This makes sense, since the value could feasibly be read on the 1st iteration of the loop and then not read on subsequent iterations. However, this also only makes sense to me if the loop is small. If a whole lot of stuff is done inside the loop, the compiler may have no choice but to read it every time, since it may need to use the register it is caching the loop constraint variable in, right?

    If I have some loop that does A LOT of stuff, like a game loop for example, if somewhere in that loop, I'm checking the value of some global that another thread updates, is it really necessary to make that global volatile? Everything I've read says yes, but everything I've read only presents extremely simplistic scenarios.

  2. #2
    Registered User
    Join Date
    Sep 2004
    Location
    California
    Posts
    3,267
    It's best to declare it as volatile since that is the behavior you want. Just because today's compilers are not utilizing a register to store your flag doesn't mean that will be the case for future versions.
    bit∙hub [bit-huhb] n. A source and destination for information.

  3. #3
    Registered User
    Join Date
    Jun 2005
    Posts
    6,815
    volatile tells the compiler a variable may change in a manner not visible to the compiler. The compiler therefore does not try to "optimise away" any statements that access said variable.

    That said, there are practical cases where volatile is neither necessary nor sufficient if the variable is being modified by another thread. You need to use explicit synchronisation (mutex, critical section, etc).
    Right 98% of the time, and don't care about the other 3%.

    If I seem grumpy or unhelpful in reply to you, or tell you you need to demonstrate more effort before you can expect help, it is likely you deserve it. Suck it up, Buttercup, and read this, this, and this before posting again.

  4. #4
    C++まいる!Cをこわせ!
    Join Date
    Oct 2007
    Location
    Inside my computer
    Posts
    24,654
    volatile is not sufficient for protecting a variable from multiple threads. Said variable may be stored in write-back buffers, registers, caches and these things are not necessarily visible to other cores. Furthermore, nothing in the standard says that writes to a volatile variable are required to be flushed to memory. This means you cannot guarantee that a volatile variable will be synchronized. volatile was invented to talk to memory-mapped hardware where the value of some read memory may change by the hardware between reads.
    If you want to read/write to a variable shared between threads, you need to use atomics or locks. Also, volatile reads/writes between different threads are undefined behavior, whereas atomics and locks are not.
    Quote Originally Posted by Adak View Post
    io.h certainly IS included in some modern compilers. It is no longer part of the standard for C, but it is nevertheless, included in the very latest Pelles C versions.
    Quote Originally Posted by Salem View Post
    You mean it's included as a crutch to help ancient programmers limp along without them having to relearn too much.

    Outside of your DOS world, your header file is meaningless.

  5. #5
    Registered User
    Join Date
    Nov 2008
    Posts
    127
    Quote Originally Posted by grumpy View Post
    volatile tells the compiler a variable may change in a manner not visible to the compiler. The compiler therefore does not try to "optimise away" any statements that access said variable.

    That said, there are practical cases where volatile is neither necessary nor sufficient if the variable is being modified by another thread. You need to use explicit synchronisation (mutex, critical section, etc).
    I've seen this said a lot too. But I don't see why using a mutex around accessing a shared resource would help. AFAIK, all using a mutex does is ensure exclusive access to it. But if the compiler decides to cache the value somehow, it wouldn't really matter if it had exclusive access when reading it if the compiler optimized out the read.

    Quote Originally Posted by Elysia
    volatile is not sufficient for protecting a variable from multiple threads. Said variable may be stored in write-back buffers, registers, caches and these things are not necessarily visible to other cores.
    Multiple threads doesn't necessarily mean there are multiple cores. Would you say this holds true with multiple threads on a single core?

    Quote Originally Posted by Elysia
    volatile was invented to talk to memory-mapped hardware where the value of some read memory may change by the hardware between reads.
    This makes me think that volatile is not necessary in my case. Which is good, because I don't want to use volatile. However, unless I'm misunderstanding it, this Dr. Dobb's article seems to suggest I should, which is where the question came from. volatile: The Multithreaded Programmer's Best Friend | Dr Dobb's

  6. #6
    C++まいる!Cをこわせ!
    Join Date
    Oct 2007
    Location
    Inside my computer
    Posts
    24,654
    Quote Originally Posted by homer_3 View Post
    I've seen this said a lot too. But I don't see why using a mutex around accessing a shared resource would help. AFAIK, all using a mutex does is ensure exclusive access to it. But if the compiler decides to cache the value somehow, it wouldn't really matter if it had exclusive access when reading it if the compiler optimized out the read.
    A mutex has an implicit memory barrier, which would ensure all operations are flushed to memory before it leaves the critical section.

    Quote Originally Posted by homer_3 View Post
    Multiple threads doesn't necessarily mean there are multiple cores. Would you say this holds true with multiple threads on a single core?
    Yep.
    Consider some code:

    Thread 1:
    int x, y; // y is shared between threads
    x = y;

    Thread 2:
    y++;

    Thread 3:
    y++;

    What is the possible values of x, assuming y is 0 from the beginning? Remember that no registers are shared between threads, so the value of y could be cached in a register and thread 1 would never know. But let's assume that the compiler does not cache it in a register. Then it would load y, increment, write back. But what happens if you get a context switch just after thread 2 loads y? Thread 3 could load y, increment, write back, and then thread 2 could increment the value cached in the register and write back. You have a race condition. volatile does not guarantee that the 3 operations load, increment and store are done as an atomic operation. All it guarantees is that the compiler will not cache the value in a register, but actually do a read from memory (or cache) for every read.

    Quote Originally Posted by homer_3 View Post
    This makes me think that volatile is not necessary in my case. Which is good, because I don't want to use volatile. However, unless I'm misunderstanding it, this Dr. Dobb's article seems to suggest I should, which is where the question came from. volatile: The Multithreaded Programmer's Best Friend | Dr Dobb's
    The article is too old. Pre-2011, C++ knew nothing about threads, and there were hardly any multi-core architectures either. I haven't through it to the end, though. But C++11 radically changed the landscape.
    Quote Originally Posted by Adak View Post
    io.h certainly IS included in some modern compilers. It is no longer part of the standard for C, but it is nevertheless, included in the very latest Pelles C versions.
    Quote Originally Posted by Salem View Post
    You mean it's included as a crutch to help ancient programmers limp along without them having to relearn too much.

    Outside of your DOS world, your header file is meaningless.

  7. #7
    Master Apprentice phantomotap's Avatar
    Join Date
    Jan 2008
    Posts
    5,108
    Which is good, because I don't want to use volatile. However, unless I'm misunderstanding it, this Dr. Dobb's article seems to suggest I should, which is where the question came from. volatile: The Multithreaded Programmer's Best Friend | Dr Dobb's
    O_o

    If you search for "Alexandrescu volatile", you'll find hundreds of articles describing how he was wrong.

    *shrug*

    I decided to test the issue myself, feel free to do the same, a while back.

    I will not now again post all of the results, but I'll give an overview.

    I tested many, many compilers for many different environments each against several types (I coded some good and bad examples each using `volatile' and not using `volatile' with and without synchronization primitives.) of code.

    The `volatile' keyword did nothing of threading value even once. Now to be clear, I did specifically write some code which people would think of as having the caching problem `volatile' is supposed to solve. The `volatile' keyword, again, changed nothing. The good examples which were compiled correctly worked with or without the `volatile' keyword.

    To be fair, three test cases did result in correct code (I explored the generated assembler code.) using `volatile' without synchronization primitives. These "successful" cases were limited to two compilers. (That is, one compiler didn't even produce correct code for one sample.) In all successful cases, the compiler inserted a proper memory fence around accesses to the variable in question. In other words, the compiler simply inserted code that you as the programmer should have simply written in the first place.

    In the interest of disclosure, a few good examples were compiled to an incorrect binary. However, the use of the `volatile' keyword still changed nothing. The cases where the binary was bad remained bad even throwing `volatile' across the variable in question.

    If you correctly use synchronization primitives, the `volatile' keyword isn't going to buy you anything worth having in the context of threading.

    But C++11 radically changed the landscape.
    That is certainly true on the face of it, but the C++11 standard didn't change anything with respect to this situation of the `volatile' and threading issue.

    The C++11 standard says approximately "do not use `volatile' for threaded communication".

    [Edit]
    Seems I read that in compiler documentation: http://msdn.microsoft.com/en-us/library/12a04hfd.aspx
    [/Edit]

    The use of C++11 does place guarantees about `volatile' reads, writes, and optimization which helps with the original intended purpose. However, the original use has nothing to do with threads. In other words, the C++11 version of `volatile' still has nothing to do with threads.

    With the C++11 standard, `volatile' exerts more control over what the compiler may do with the code. The C++11 standard control of the memory model effectively ends at the compiler. The behavior of the compiler is fixed, but the behavior of the controllers and processor is not.

    Soma
    Last edited by phantomotap; 12-18-2014 at 09:50 AM.
    “Salem Was Wrong!” -- Pedant Necromancer
    “Four isn't random!” -- Gibbering Mouther

  8. #8
    C++まいる!Cをこわせ!
    Join Date
    Oct 2007
    Location
    Inside my computer
    Posts
    24,654
    I meant to imply more of the lines of while volatile may have helped in some situations prior C++-11 (which honestly I don't think it does), C++11 added proper synchronization mechanisms which are guaranteed to work with the standard, which makes volatile pointless for threading mechanisms in the new standard (if it even worked in the beginning).
    Quote Originally Posted by Adak View Post
    io.h certainly IS included in some modern compilers. It is no longer part of the standard for C, but it is nevertheless, included in the very latest Pelles C versions.
    Quote Originally Posted by Salem View Post
    You mean it's included as a crutch to help ancient programmers limp along without them having to relearn too much.

    Outside of your DOS world, your header file is meaningless.

  9. #9
    Master Apprentice phantomotap's Avatar
    Join Date
    Jan 2008
    Posts
    5,108
    I meant to imply more of the lines of while volatile may have helped in some situations prior C++-11 (which honestly I don't think it does), C++11 added proper synchronization mechanisms which are guaranteed to work with the standard, which makes volatile pointless for threading mechanisms in the new standard (if it even worked in the beginning).
    O_o

    Ah, I see; I agree.

    One should definitely use synchronization primitives, and C++11 makes the pretty easy.

    Soma
    “Salem Was Wrong!” -- Pedant Necromancer
    “Four isn't random!” -- Gibbering Mouther

  10. #10
    Registered User
    Join Date
    Jun 2005
    Posts
    6,815
    Quote Originally Posted by homer_3 View Post
    I've seen this said a lot too. But I don't see why using a mutex around accessing a shared resource would help. AFAIK, all using a mutex does is ensure exclusive access to it. But if the compiler decides to cache the value somehow, it wouldn't really matter if it had exclusive access when reading it if the compiler optimized out the read.
    Mutexes actually enable exclusive access to sections of code, not variables. Those sections of code might access variables. Those sections of code are also serialised (if one section is executing, others are forced to wait). If a compiler cached the value somehow and "optimized out the read" past a mutex (entering or leaving) then it would not be possible to use mutexes to enable safe sharing of data between threads (among other things). The compiler would be broken.

    As Elysia said, there is an implicit memory barrier.

    That said, as Soma's post (#7) demonstrates, there are buggy compilers.
    Right 98% of the time, and don't care about the other 3%.

    If I seem grumpy or unhelpful in reply to you, or tell you you need to demonstrate more effort before you can expect help, it is likely you deserve it. Suck it up, Buttercup, and read this, this, and this before posting again.

  11. #11
    Registered User MutantJohn's Avatar
    Join Date
    Feb 2013
    Posts
    2,665
    I'm not sure if I read this topic correctly but isn't volatile supposed to mean that every memory access comes directly from the system memory or RAM?

    So assuming the example from the OP, if a game-loop reads a volatile variable that is written to with proper mutex/atomic operations from separate threads, doesn't the game loop not need anything special? Or does it need a mutex to prevent it from reading while another thread is still writing to that address?

  12. #12
    C++まいる!Cをこわせ!
    Join Date
    Oct 2007
    Location
    Inside my computer
    Posts
    24,654
    I suppose that maybe in theory, volatile and a write flush barrier might be sufficient to ensure that it works, but it's still undefined behavior according to the standard. If you are reading a 4-8 byte variable (depending on architecture), then you won't likely ever read a partially written variable, so it probably works. But if it's more than 4-8 bytes, then you could be reading a partially written object (so in this case, you need a mutex).
    Quote Originally Posted by Adak View Post
    io.h certainly IS included in some modern compilers. It is no longer part of the standard for C, but it is nevertheless, included in the very latest Pelles C versions.
    Quote Originally Posted by Salem View Post
    You mean it's included as a crutch to help ancient programmers limp along without them having to relearn too much.

    Outside of your DOS world, your header file is meaningless.

  13. #13
    Registered User
    Join Date
    Oct 2006
    Posts
    3,445
    Quote Originally Posted by MutantJohn View Post
    Or does it need a mutex to prevent it from reading while another thread is still writing to that address?
    It needs a mutex, because it may read from the memory location while the write operation is partially complete. Proper use of a mutex ensures that the write operation is complete before any read operations begin.
    What can this strange device be?
    When I touch it, it gives forth a sound
    It's got wires that vibrate and give music
    What can this thing be that I found?

  14. #14
    Registered User MutantJohn's Avatar
    Join Date
    Feb 2013
    Posts
    2,665
    Wait, I thought only one thread at a time had access to the RAM. If a thread is directly writing to RAM and then another thread is attempting to read that variable (which has been declared volatile), doesn't that make it safe because it has to wait for the writing thread to release its grip of the RAM? Or am I thinking of this wrong? I swear to God, I've been pwned by that memory blocking thing in the past. Maybe it's only for threads writing. Only one thread can write but any number of threads can read RAM.

  15. #15
    Registered User
    Join Date
    May 2010
    Posts
    4,532
    I'm not sure if I read this topic correctly but isn't volatile supposed to mean that every memory access comes directly from the system memory or RAM?
    Yes. But this doesn't prevent the problems encountered when dealing with multiple threads. And also note a volatile qualified variable can exhibit the same types of problems caused by multiple threads, within a single thread, especially if the "external" source is a rapidly varying value.

    Without a mutex it is possible to read a value partially written by a different thread. Remember most variables are actually contained in multiple memory locations. These individual memory locations are not written or read at the exact same time. A mutex is used to insure the thread has exclusive access to the entire memory region the variable occupies until the thread is finished reading or writing that variable.

    Jim

Popular pages Recent additions subscribe to a feed

Similar Threads

  1. what is volatile variable?
    By shansajid in forum C Programming
    Replies: 2
    Last Post: 02-14-2013, 07:21 AM
  2. volatile modifier
    By veera in forum C Programming
    Replies: 4
    Last Post: 08-12-2012, 01:59 AM
  3. To Volatile, or not to Volatile?
    By EVOEx in forum C++ Programming
    Replies: 16
    Last Post: 05-12-2012, 02:07 PM
  4. fork volatile question
    By rotis23 in forum Linux Programming
    Replies: 2
    Last Post: 04-07-2004, 07:31 AM
  5. volatile??
    By jacktibet in forum C Programming
    Replies: 2
    Last Post: 05-29-2003, 03:46 PM