March 26, 2018
Everywhere I look the advice is to avoid atomic and just mutex things.

Why is this `a.atomicStore(b)`(memory order is seq) less safe than `synchronized{a=b}`?  I get that when more operations or shared values are used it is appropriate to mutex the entire set of operations but why would I for a single set?

If the first is in fact less safe that the second then I am eager to learn more, could you recommend a book or paper on the subject?

Thanks!
March 26, 2018
On Monday, March 26, 2018 23:15:42 Jonathan via Digitalmars-d-learn wrote:
> Everywhere I look the advice is to avoid atomic and just mutex things.
>
> Why is this `a.atomicStore(b)`(memory order is seq) less safe than `synchronized{a=b}`?  I get that when more operations or shared values are used it is appropriate to mutex the entire set of operations but why would I for a single set?
>
> If the first is in fact less safe that the second then I am eager to learn more, could you recommend a book or paper on the subject?

I think that what it mostly comes down to is that it's harder to get atomics right than it is to get mutexes right. It can be very difficult to write lock-free code - especially when you're dealing with more complicated objects like containers. It can already be surprisingly difficult to get mutexs right. People screw up thread-safety stuff all the time. The fact that D uses thread-local by default reduces the problem, but then folks frequently get annoyed with the restrictions that shared has and end up using __gshared, throwing away all of the protections and risking bugs due to the fact that the compiler assumes that the objects are thread-local. The biggest thing that you can do in a program to make it thread-safe is to make as much as possible thread-local and have as little as possible shared between threads. Also, it's frequently considered better practice to use message passing such as you get with std.concurrency than directly sharing data.

Unfortunately, I don't really have any reading that I could recommend on the subject. There's always the section on concurrency in TDPL (which IIRC is a chapter which is actually available for free), but it's mostly talking about the D-specific issues and doesn't say anything about atomics (IIRC, core.atomic didn't even exist when TDPL was written). I expect that there are quite a few resources online talking about C++ atomics though. IIRC, their API goes about things in a different way, but the basic concepts are the same. All of the basic concepts are the same in C++ as they are in D. It's just that D objects are thread-local by default, which means that the type system helps you keep things thread-safe in a way that C++ doesn't. With shared, you're generally forced to cast it away while the mutex is locked, whereas in C++, since there is no shared, it just lets you muck with shared objects as if they were thread-local without any casting. In D, atomics are pretty much the only way to do much with shared without casting it away in protected sections of code.

- Jonathan M Davis