Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Is double read atomic on an Intel architecture?

Tags:

c#

.net

intel

My colleague and I are having an argument on atomicity of reading a double on an Intel architecture using C# .NET 4.0. He is arguing that we should use Interlocked.Exchange method for writing into a double, but just reading the double value (in some other thread) is guaranteed to be atomic. My argument is that .NET doesn't guarantee this atomicity, but his argument is that on an Intel architecture this is guaranteed (maybe not on AMD, SPARC, etc.).

Any Intel and .NET experts share some lights on this?

Reader is OK to read a stale (previous) value, but not incorrect value (partial read before and after write giving a garbage value).

like image 923
Alok Avatar asked Jul 14 '14 07:07

Alok


1 Answers

My colleague and I are having an argument on atomicity of reading a double on an Intel architecture using C# .NET 4.0.

Intel guarantees that 8 byte doubles are atomic on read and write when aligned to an 8 byte boundary.

C# does not guarantee that a double is aligned to an 8 byte boundary.

He is arguing that we should use Interlocked.Exchange method for writing into a double, but just reading the double value (in some other thread) is guaranteed to be atomic.

Your colleague is not thinking this through carefully. Interlocked operations are only atomic with respect to other interlocked operations. It doesn't make any sense to use interlocked operations some of the time; this is like saying that traffic that is going through the intersection to the north doesn't have to obey the traffic light because traffic that is going through the intersection to the west does obey the traffic light. Everyone has to obey the lights in order to avoid collisions; you can't do just half.

My argument is that .NET doesn't guarantee this atomicity, but his argument is that on an Intel architecture this is guaranteed (maybe not on AMD, SPARC, etc.).

Look, suppose that argument were correct, which it isn't. Is the conclusion that we're supposed to reach here is that the several nanoseconds that is saved by doing it wrong are somehow worth the risk? Forget about interlocked. Take a full lock every time. The only time you should not take a full lock when sharing memory across threads is when you have a demonstrated performance problem that is actually due to the twelve nanosecond overhead of the lock. That is when a twelve nanosecond penalty is the slowest thing in your program and that is still unacceptable, that's the day you should consider using a low-lock solution. Is the slowest thing in your program taking a 12 nanosecond uncontended lock? No? Then stop having this argument, and spend your valuable time making the parts of your program that take more than 12 nanoseconds faster.

Reader is OK to read a stale (previous) value, but not incorrect value (partial read before and after write giving a garbage value).

Don't conflate atomicity with volatility.

The interlocked operations, and the lock statement, will both make a memory barrier that ensures that the up-to-date value is read or published. An ordinary non-volatile read or write is not required to do so; if it happens to do so, you got lucky.

If these sorts of issues interest you, a related issue that I am occasionally asked about is under what circumstances a lock around an integer access can be elided. My articles on that subject are:

  • Can I skip the lock when reading an integer?

  • Reordering optimizations

like image 149
Eric Lippert Avatar answered Sep 29 '22 05:09

Eric Lippert