3 ms·
My exception: If all operations on the shared data are atomic, and always leave it in a valid state, then you can get away without explicit synchronization. U
by danjayh 13y ago
My exception: If all operations on the shared data are atomic, and always leave it in a valid state, then you can get away without explicit synchronization. Unfortunately, the only way you can really achieve this (without some sort of a synchronization API) is to use assembly code, and take advantage of architecture-specific data access mechanisms.
- mikeash 13y agoAbsolutely true. I would say that either atomics count as a form of "synchronization", or they're advanced enough that you can disregard the One Commandment once you get to that stage.
- ddeck 13y agoAlthough atomicity helps, it typically doesn't provide any visibility guarantees, so typically some other form of synchronization or memory barrier will be required.
- spullara 13y agoThe Atomic* classes in Java give you essentially direct access to these mechanisms.
- klodolph 13y agoBut you'll need memory barriers. Let's say you have two variables, x and y, satisfying x >= y at all times, and the values of x and y are never allowed to decrease. // Thread 1 atomic_inc(&x); atomic_inc(&y); // Thread 2 local_y = atomic_read(&y); local_x = atomic_read(&x); If you go through it logically, it's always in a valid state, right? No. You need explicit synchronization. If we start at x=1, y=1, then thread 2 can see x=1, y=2, which seems impossible! Or in short, your exception sucks. (By "sucks" I mean it is not sufficiently detailed enough to prevent errors.)
- rayiner 13y agoThis is only the case on architectures where atomic operations don't imply memory barriers. On x86, there is a total order on atomic operations, do another CPU will never see the write to "y" before the write to "x". Indeed on x86, there is total order on stores, so if you had two threads like that, where one thread only did reads and the other thread did updates, you can get away with an unlocked increment (x++; y++).
- Strilanc 13y agoBeing atomic is not enough. It's too easy to use two atomics operations and assume they'll be sequentially consistent. For example, suppose we have: A = 0 B = 0 Producer: while true: AtomicIncrement A AtomicIncrement B Consumer: while true: postA = AtomicDecrement A postB = AtomicDecrement B assert postA == postB // wrong The assertion is wrong, when you're dealing with relaxed atomics. For example, the producer can be optimized into this either by the compiler or by caching layers: int savedUpA = 0 while true: savedUpA++ if (savedUpA == 100) AtomicAdd A, 100 AtomicIncrement B In which case the consumer will often see that postA != postB. Thankfully, languages are apparently converging on "every atomic write is a release barrier" and "every atomic read is an acquire barrier", which makes these sorts of optimizations illegal (releasing B's new value requires releasing A's new value).