What operations are atomic in C#?
Asked Answered
B

3

63

Is there a systematic way to know whether an operation in C# will be atomic or not? Or are there any general guidelines or rules of thumb?

Beatup answered 31/7, 2012 at 17:10 Comment(0)
D
49

For something more complete/detailed:

Reads and writes to 32-bit value types are atomic: This includes the following intrinsic value (struct) types: bool, char, byte, sbyte, short, ushort, int, uint, float. The following types (amongst others) are not guaranteed to be atomic: decimal, double, long, ulong.

e.g.

int x;
x = 10; // atomic
decimal d;

d = 10m; // not atomic

Reference assignment is also an atomic operation:

private String _text;
public void Method(String text)
{
  _text = text; // atomic
}
Demography answered 31/7, 2012 at 17:25 Comment(12)
Not strictly correct- 64 bit values (long) are also atomic if you are on a system whose native word size is 64-bits (e.g. x64 processor running a 64-bit version of windows)Weaken
Are references atomic even on a 64-bit application?Beatup
Nevermind... I think the comment by @ChrisShain answers that question.Beatup
@ChrisShain From the C# spec: "Reads and writes of other types, including long, ulong, double, and decimal, as well as user-defined types, are not guaranteed to be atomic. "Demography
@Beatup The C# spec simply says reads and writes from/to "reference types" are atomic.Demography
@PeterRitchie the C# spec says that there is no guarantee that longs are atomic, but it does not by any means forbid atomicity. My understanding is that on the 64-bit CLI they are atomic, due to the guarantees in the part of the CLI spec I post in my answer. That said, I am willing to be proven wrong if an authority on the subject can say otherwise why access to a long on a 64-bit platform would be non-atomic.Weaken
@PeterRitchie see the addition to my answer- Eric Lippert has answered this for us.Weaken
@ChrisShain you are correct, the spec does not say they are "not" atomic or "never" atomic, I've clarified my answer (which wasn't meant to suggest they were never going to be atomic, just not guaranteed). But, you'd have to compile for x64 to make sure it was. If you didn't compile for x64, the code could run in x86 and thus not be atomic; so, you'd have to assume it wasn't atomic and use lock or Monitor.Enter/Exit to ensure it was accessed atomically.Demography
Reference reads and reference writes are atomic; a reference assignment combines an (atomic) reference read and an (atomic) reference write, but the operation as a whole is not atomic.Grisette
@Grisette According to the link below, Reference Assignment is atomic. #2192624Jamnis
@fdhsdrdark: Given Object x="Foo",y="Bar";, consider what happens if if thread #1 performs x=y; at the same time as another thread performs y=x;. C#/.NET semantics (which entail an atomic read followed by an atomic write) would allow for x and y to hold Bar/Foo, Foo/Foo, or Bar/Bar. If an assignment were atomic as a complete operation, Bar/Foo would be impossible.Grisette
@fdhsdrdark: It is so rare for platforms to offer truly atomic assignments which would guarantee that no other operations can occur between the write and the read, that the term "atomic assignment" is often used to describe the non-atomic combination of an atomic read and an atomic write. The combination as a whole, however, is generally not an atomic operation, since the assignments above could be interleaaved as temp1=y; temp2=x; x=temp1; y=temp2;.Grisette
W
35

Yes. Read the CLI specification: http://www.ecma-international.org/publications/standards/Ecma-335.htm. For instance:

I.12.6.6 Atomic reads and writes

A conforming CLI shall guarantee that read and write access to properly aligned memory locations no larger than the native word size (the size of type native int) is atomic (see §I.12.6.2) when all the write accesses to a location are the same size. Atomic writes shall alter no bits other than those written. Unless explicit layout control (see Partition II (Controlling Instance Layout)) is used to alter the default behavior, data elements no larger than the natural word size (the size of a native int) shall be properly aligned. Object references shall be treated as though they are stored in the native word size.

[Note: There is no guarantee about atomic update (read-modify-write) of memory, except for methods provided for that purpose as part of the class library (see Partition IV). An atomic write of a “small data item” (an item no larger than the native word size) is required to do an atomic read/modify/write on hardware that does not support direct writes to small data items. end note]

[Note: There is no guaranteed atomic access to 8-byte data when the size of a native int is 32 bits even though some implementations might perform atomic operations when the data is aligned on an 8-byte boundary. end note]

Regarding the 64-bit long question, Eric Lippert answers it here: https://ericlippert.com/2011/05/31/atomicity-volatility-and-immutability-are-different-part-two/

The CLI specification actually makes stronger guarantees. The CLI guarantees that reads and writes of variables of value types that are the size (or smaller) of the processor's natural pointer size are atomic; if you are running C# code on a 64 bit operating system in a 64 bit version of the CLR then reads and writes of 64 bit doubles and long integers are also guaranteed to be atomic. The C# language does not guarantee that, but the runtime spec does. (If you are running C# code in some environment that is not implemented by some implementation of the CLI then of course you cannot rely upon that guarantee; contact the vendor who sold you the runtime if you want to know what guarantees they provide.)

Another subtle point about atomic access is that the underlying processor only guarantees atomicity when the variable being read or written is associated with storage that is aligned to the right location in memory. Ultimately the variable will be implemented as a pointer to memory somewhere. On a 32 bit operating system, that pointer has to be evenly divisible by 4 in order for the read or write to be guaranteed to be atomic, and on a 64 bit operating system it has to be evenly divisible by 8.

Weaken answered 31/7, 2012 at 17:11 Comment(1)
Eric does say that "The C# language does not guarantee that." w.r.t. 64-bit values and atomicity... Only under one specific CLI is this a possibility. Pedantic; but the OP doesn't specify which CLI...Demography
C
8

From the CLI specifications you can get here:

"A conforming CLI shall guarantee that read and write access to properly aligned memory locations no larger than the native word size (the size of type native int) is atomic…”

Section 12.5 from the C# specification here:

“Reads and writes of the following data types shall be atomic: bool, char, byte, sbyte, short, ushort, uint, int, float, and reference types.” Also: “…there is no guarantee of atomic read-modify-write, such as in the case of increment or decrement.”

Make the increment operation atomic with this.

Colatitude answered 31/7, 2012 at 17:20 Comment(1)
Except in the Interlocked class, which does have atomic increment, decrement, and several others.Benthamism

© 2022 - 2024 — McMap. All rights reserved.