0

Update: First of all, please kindly note that this question does neither involve threading, nor is it about re-ordering or fence-related. Therefore, this does not answer my question (although it's a similar question with an accepted answer): Why is volatile deprecated in C++20?

I guess that there is something important worth clarifying: If you want your code thread-safe, then in many cases, it's not sufficient, to ONLY use volatile. Additional or alternative techniques are required (atomic, lock, etc.). Anyway this question is not about thread-safety.


I recently started my first huge embedded C++ project (with some parts still in C), after many years of pure C with some (inline-)assembler. So far it looks like a good choice: no major performance problems, but tons of optional nice techniques not availabe in C.

Today i wanted to use bind_front, so i needed to switch to C++20, and was surprised by a huge bunch of "volatile"-related warnings, which is especially unpleasent, as i prefer warning-free code (with all warnings switched on in the compiler).

Apparently some things i sometimes do, are "wrong" in the new standard:

Example1:

for (volatile int i=0; i<10; i++);           // very short delay (no alternative way available)

Example2:

...
port->ctrl |= 0x3;                           // setting some bits in some volatile HW register

In both examples, the volatile keyword is merely used to keep the compiler from optimizing-away the code.

Here is some background, but not really an explanation for the "why": https://blog.feabhas.com/2021/05/modern-embedded-c-deprecation-of-volatile/

And this still contains no satisfactory explanation: https://www.youtube.com/watch?v=KJW_DLaVXIY (C++ committee language evolution chair )

I agree with the common perception, that some implications of volatile might be difficult to understand, expecially to beginners or programmers that are "far away" form the hardware. We know that in a system in which two or more masters can do write access to port->ctrl at random time, the read-modify-write access wouldn't be safe just by using volatile. But in some other system, port->ctrl might be a common read/write hardware register, for which the read-modify-write access actually is safe.

Up to now, port->ctrl |= 0x3 seemed semantically exactly the same as port->ctrl = port->ctrl | 0x3; But now, only the latter compiles without warning.

Worst thing for me: Sooner or later, i'll have to change tons of perfectly stable and good readable code. But i fail to recognize any improvement. Actually, the opposite is true: not able to use the shortcut op=, many of the code lines become much longer, and also redundant, and overall more error-prune.

What do i miss? Can someone enlighten me?

  • 4
    Does this answer your question? [Why is volatile deprecated in C++20?](https://stackoverflow.com/questions/59223814/why-is-volatile-deprecated-in-c20) – user17732522 Dec 25 '21 at 15:01
  • 2
    It is only certain uses of `volatile` that are deprecated (although the paper introduces these was titled "Deprecating volatile"). Specifically in your examples it is not obvious that `port->ctrl |= 0x3` and `port->ctrl = port->ctrl | 0x3;` are equivalent. The latter clearly access the memory once for a load and another time for a store, but the former looks as if it accesses the memory only once for a combined load/store. – user17732522 Dec 25 '21 at 15:05
  • 2
    @user17732522 The C++ language standard (in the "expr.ass" section) made pretty clear that those two lines were equivalent, and l think most programmers understood that. There is no objective reason why one of those lines needs to be deprecated and not the other, but I guess we just have to watch the [one-hour talk by JF Bastien](https://www.youtube.com/watch?v=KJW_DLaVXIY) to see why he wanted to change the standard. – David Grayson Dec 25 '21 at 15:42
  • @DavidGrayson My understanding is that the change is to avoid common misinterpretation of the syntax, not that the specification was ambiguous. I am not saying that I agree with the change, but that was the rational given in the paper introducing the change and I don't have any further details. – user17732522 Dec 25 '21 at 16:20
  • @user17732522: Thanks for your help! - Well, of course, we shouldn't rely on the use of volatile when we actually need atomicity or a fence (btw: in embedded projects, i've never ever experienced any re-ordering of code lines). Anyway there are good examples for the proper use of volatile. So i still think that it's a bad idea to take it away or replace it by less handy techniques. – Albert -Al- Hollmann Dec 25 '21 at 16:38
  • @DavidGrayson: Thanks for your clarification. - Well, if volatile is really such an incomprehensible thing to most programmers, then hopefully in the next standard they will replace it by something better, instead of taking it away in little slices, as some discussions imply. – Albert -Al- Hollmann Dec 25 '21 at 16:48
  • @Albert-Al-Hollmann: "*First of all, please kindly note that this question does neither involve threading, nor is it about re-ordering or fence-related*" Irrelevant. While *your* code may not care about fencing or re-ordering, other people's uses of `volatile` do. And the compiler cannot know the difference between a person who expects `|=` to be atomic and a person who doesn't. Thus, the question and answer seem entirely appropriate to you, even if you aren't using `volatile` like that. – Nicol Bolas Dec 25 '21 at 17:25
  • @Albert-Al-Hollmann: "*And this still contains no satisfactory explanation*" What would you consider a "satisfactory explanation"? That is, what do you find un-"satisfactory" about it? The change was made for code that isn't yours. But it still affects you because it's impossible for the language to know your intent. – Nicol Bolas Dec 25 '21 at 17:27
  • @Nicol Bolas: Thanks for your comments! AFAIK, both port->ctrl |= 0x3 and port->ctrl = port->ctrl | 0x3 will compile to identical machine code, and are both non-atomic on many machines. Volatile will never lead to atomic behaviour, right? Well, maybe i miss something here? – Albert -Al- Hollmann Dec 25 '21 at 17:48
  • 1
    @Albert-Al-Hollmann: "*Volatile will never lead to atomic behaviour, right?*" Yes, but a lot of people don't realize that. The point of deprecating these uses is so that people will be forced to *prove* that they know it's not atomic by spelling it out in a way that cannot possibly be atomic. That is, the change was not made to stop *you*, but it does *affect* you. – Nicol Bolas Dec 25 '21 at 17:53
  • @NicolBolas: Okay, i get your point. Well, it still feels to me like C++ being "dumbed down" instead of refined. I doubt that this change will really help beginners, but let's hope for it anyway, right? - @ y'all: thanks for helping me understand this thing. For now, i guess i'll have to go with -Wno-deprecated, if i want to stick to my beloved |=. And for the future, let's hope for C++ standard changes that doesn't require the change of our existing code... - Cheers and happy holidays! – Albert -Al- Hollmann Dec 25 '21 at 18:23
  • @Albert-Al-Hollmann: "*I doubt that this change will really help beginners*" It's not really meant to "help beginners". The roots of "volatile as atomic" are *deep*, and many long-time C++ programmers believe this. What is at worst a small annoyance to some can fix tons of bugs from others. It's not like you cannot do what you need to do; you just have to spell it slightly differently. – Nicol Bolas Dec 25 '21 at 18:34
  • 1
    I expect even if ISO C++ fully removes `|=` for `volatile`, implementations like GCC will still have options to allow compiling existing code that uses it, exactly because of use-cases like yours of existing code-bases. (And from people that *do* understand exactly what `volatile` does and doesn't do, and want more compact syntax without having to write and use helper functions like `or_into_volatile(volatile T &lhs, T rhs)` if that even works.) – Peter Cordes Dec 25 '21 at 18:42
  • IDK what you're hoping for with your further edits to this SO question; the ISO C++ change is a fact, motivated by arguably-weak reasons totally separate from your use-case, which make things worse for your use-case. That doesn't change the facts about what the motivation / reasons for the change were. AFAIK, there isn't an explanation that makes sense from the embedded development perspective, other than "you have to suffer because we thought there might be misconceptions about `++` on `volatile` non-`atomic` objects, or something like that. – Peter Cordes Dec 25 '21 at 18:45
  • @PeterCordes: It should be noted that what people "thought" is not at play here. It is well known that many C++ programmers believe that `volatile` means atomic. There are several extremely popular questions on this very sight about precisely that, and several answers that got upvotes from people who genuinely believe this. You can argue against the resolution or the cost/benefit for all C++ programmers at large, but you shouldn't claim that the problem doesn't exist. – Nicol Bolas Dec 25 '21 at 18:55
  • 2
    @NicolBolas: I know people believe `volatile` is useful or relevant for multithreading (like in [When to use volatile with multi threading?](https://stackoverflow.com/q/4557979)), but I thought a lot fewer of those people had the false idea that `++` would do an atomic RMW. I haven't come across that very often, and it's obviously non-atomic in easily testable ways even on x86. (I'm not saying you're wrong, just that *I* haven't seen much evidence of it, so if you could remind me with a link, that'd be great.) – Peter Cordes Dec 25 '21 at 21:53
  • 1
    I watched [JF Bastien's talk](https://www.youtube.com/watch?v=KJW_DLaVXIY) and he didn't give any examples of people other than himself who were confused by what `|=` means. – David Grayson Dec 25 '21 at 23:07

0 Answers0