4 ms·
I guess there must be at least one book about the Java Memory Model, which is very different but fascinating? I don't know of any specific books to recommend.
by tialaramex 2y ago
I guess there must be at least one book about the Java Memory Model, which is very different but fascinating? I don't know of any specific books to recommend.
For many languages there is nothing resembling this, they tend to not get into the details Mara covers, if you get a mutex and maybe atomic arithmetic then they're done.
If you wondered about C or C++, this book is the same content as for those languages but with Rust's syntax. The discrepancy between Rust's memory model and the memory model adopted in C++ 11 and subsequently C is mostly about a feature that's not available in your C or C++ compiler and (which is why Rust doesn't have it) probably won't ever be.
C++ x.store(r1, std::memory_order_relaxed);
is literally the same thing as
Rust x.store(r1, std::sync::atomic::Ordering::Relaxed);
The biggest syntax difference is that C++ x.store(r1) compiles, and in Rust it doesn't. But, chances are after reading Mara's book you will think it's weird not to specify the Ordering needed and never use this uh, convenience.
- freddierest 2y agoThe classic for Java is "Java Concurrency in Practice", a great book for more than just Java. Java's happens-before memory model is similar to C++'s. I'll prob get this book, if only for the memory model chapter.
- ibraheemdev 2y agoJava atomics are actually sequentially consistent. C# relaxes this to acquire/release. Though the general concept of happens-before is still immensely useful for learning atomics as sequential consistency is a superset of acquire/release.
- freddierest 2y agoThanks for correction/clarification. Much as C# has a weaker memory model than Java, my mental model for memory models is weaker than I thought. Where do Rust and C++ lie wrt C# and Java?
- jcranmer 2y agoAll of the memory models in question are based on data-race-free, which says (in essence) that as long as all cross-thread interactions follow happens-before, then you can act as if everybody is sequentially-consistent. The original Java 5 memory model only offered sequentially-consistent atomics to establish cross-thread happens-before in a primitive way. The C++11 memory model added three more kinds of atomics: acquire/release, consume/release (which was essentially a mistake [1]), and relaxed atomics (which, to oversimplify, establish atomicity without happens-before). Pretty much every memory model since C++11--which includes the Rust memory model--has based its definition on that memory model, with most systems defaulting an otherwise unadorned atomic operation to sequentially-consistent. Even Java has retrofitted ways to get weaker atomic semantics [2]. As a practical matter, most atomics could probably safely default to acquire/release over fully sequentially-consistent. The main difference between the two is that sequentially-consistent is safer if you've got multiple atomic variables in play (e.g., you're going with some fancy lockless algorithm), whereas acquire/release tends to largely be safe if there's only one atomic variable of concern (e.g., you're implementing locks of some kind). [1] A consume operation is an acquire, but only for loads data-dependent on the load operation. This is supposed to represent a situation that requires no fences on any system not named Alpha, but it turns out for reasons™ that compilers cannot reliably preserve source-level data dependencies, so no compiler really implemented consume/release. [2] Even Java 5 may have had it in sun.misc.Unsafe; I was never familiar with that API, so I don't know for certain.
- gpderetta 2y ago> as long as all cross-thread interactions follow happens-before, then you can act as if everybody is sequentially-consistent. I don't think that's the actual guarantee. You can enforce happens-before with just acquire/release, but AFIK that's not enough to recover SC in the general case[1]. As far as I understand, The Data Race Free - Sequentially Consistent memory model (DRF-SC) used by C++11 (and I think Java), says that as long as all operation on atomics are SC and the program is data-race-free, then the whole program can be proven to be sequentially consistent. [1] but it might in some special cases, for example when all operations are mutex lock and unlock.