5 ms·
> semantics of "volatile" in C++ or Java But the semantics of "volatile" are completely different in C++ and Java! And I've seen lots of bugs from people assum
by exDM69 5y ago
> semantics of "volatile" in C++ or Java
But the semantics of "volatile" are completely different in C++ and Java! And I've seen lots of bugs from people assuming Java semantics for volatile in C++.
In C++ land, volatile is mostly useless and sometimes harmful (see [0]). It's dangerous to use it in concurrent code and hardly ever useful for memory mapped i/o without appropriate memory barriers (which make the volatile qualifier redundant).
In Java land, volatile can actually provide some useful guarantees when it comes to multithreaded uses but afaik they will usually just be turned into atomic load/store instructions so you might as well be writing atomics explicitly.
And it can be debated whether "volatile" should be a type qualifier in the first place. I would argue that it's better to make load/store operations on volatile memory explicit (for those very rare cases when you need it).
There is experimental support in Rust for the latter, `volatile_load` and `volatile_store` in `std::intrinsics` [1].
But still, doing volatile loads and stores in multithreaded code is hardly ever the right thing to do, at least without accompanying them with the relevant memory barriers (which are especially important on ARM CPUs).
[0] https://github.com/torvalds/linux/blob/master/Documentation/process/volatile-considered-harmful.rst https://github.com/torvalds/linux/blob/master/Documentation/...
[1] https://doc.rust-lang.org/std/intrinsics/fn.volatile_store.html https://doc.rust-lang.org/std/intrinsics/fn.volatile_store.h...
- tialaramex 5y ago> There is experimental support in Rust for the latter It's not really experimental. You've linked the underlying core intrinsic, but the stabilised interface, which is what programmers should actually use, is std::ptr::write_volatile / std::ptr::read_volatile Essentially you linked an implementation detail and that's why it's labelled unstable and you can't use it in stable Rust.
- exDM69 5y agoI see, thanks for the clarification. My search engine pointed me to the std::intrinsics as first hit. But yeah, you can have your volatile in Rust then. It's not a type level annotation, but an explicit (unsafe) operation.
- masklinn 5y ago> which make the volatile qualifier redundant That's not entirely true e.g. `read;read` can be very relevant in an MMIO context (a read can have side-effect), but atomic reads can technically be optimised out (though it might not currently be done by most compilers).
- exDM69 5y ago> but atomic reads can technically be optimised out (though it might not currently be done by most compilers). The memory model should explicitly forbid this optimization, especially if you use an explicit memory ordering with your loads and stores. I'm not 100% sure what the default (sequential consistency) does in this case. And if you do `read(); barrier(); read(); barrier();` like you should on most CPU architectures, the compiler definitely is not allowed to reorder the reads (barriers affect the compiler AND the CPU). Which barrier you need depends on the MMIO semantics and CPU architecture you're on. Adding volatile does not change this but may inhibit other, useful optimization. In your example of `volatile_read(); volatile_read()`, the compiler is not allowed to optimize or reorder the loads but the CPU is still allowed to reorder them with each other or other instructions. Adding `volatile` does not make this example work.
- masklinn 5y ago> The memory model should explicitly forbid this optimization, especially if you use an explicit memory ordering with your loads and stores. It has no reason to. Reading the same location twice, even atomically, has no “reason” to change the value so reusing the same read is perfectly valid. If there is an other operation between the two and that has a sequencing implication then yes, otherwise no. > In your example of `volatile_read(); volatile_read()`, the compiler is not allowed to optimize or reorder the loads but the CPU is still allowed to reorder them with each other If there are memory reads then sure but i’m assuming actual mmio here (since volatile is otherwise useless) and i’d think an mmio implementation which reorders mmio reads is completely broken.
- exDM69 5y ago