Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Atomicity of C# Coalescing Operator

I ran into some singleton code today in our codebase and I wasn't sure if the following was thread-safe:

public static IContentStructure Sentence{ 
    get {
       return _sentence ?? (_sentence = new Sentence()); 
    }
}

This statement is equivalent to:

if (_sentence != null) {
       return _sentence;
}
else {
    return (_sentence = new Sentence());
}

I believe that ?? is just a compiler trick and that the resulting code is still NOT atomic. In other words, two or more threads could find _sentence to be null before setting _sentence to a new Sentence and returning it.

To guarantee atomicity, we'd have to lock that bit of code:

public static IContentStructure Sentence{ 
    get {

       lock (_sentence) { return _sentence ?? (_sentence = new Sentence()); }
    }
}

Is that all correct?

like image 605
Adam Avatar asked Feb 23 '12 19:02

Adam


People also ask

What is the atomicity of C in co2?

The carbon atom has four valence electrons. It shares two electrons with one oxygen atom and two with another oxygen atom. So the total number of atoms in a molecule of carbon dioxide is 3. Hence the atomicity of carbon dioxide is 3.

What is atomicity of P?

Atomicity of Phosphorus is 4.

What is the atomicity of C 286?

Let us now take example of Carbon dioxide molecule ($C{O_2}$) , in Carbon dioxide ($C{O_2}$) there is one atom of carbon ( C ) and two atoms of oxygen ( O ) So atomicity of Carbon dioxide molecule ( $C{O_2}$) will be 2 + 1 = 3 . So the answer to this question is 8 that is atomicity of ethane ${C_2}{H_6}$.

What is the atomicity of 2?

The atomicity of oxygen is 2.


1 Answers

I ran into some singleton code today in our codebase

Do you have such obfuscated code throughout your codebase? This code does the same thing:

if (_s == null) 
    _s = new S();
return _s;

and is about a thousand times easier to read.

I believe that ?? is just a compiler trick and that the resulting code is still NOT atomic

You are correct. C# makes the following guarantees of atomicity:

Reads and writes of the following data types are atomic: bool, char, byte, sbyte, short, ushort, uint, int, float, and reference types. In addition, reads and writes of enum types with an underlying type in the previous list are also atomic. Reads and writes of other types, including long, ulong, double, and decimal, as well as user-defined types, are not guaranteed to be atomic. Aside from the library functions designed for that purpose, there is no guarantee of atomic read-modify-write, such as in the case of increment or decrement.

The null coalescing operator is not on that list of guarantees.

To guarantee atomicity, we'd have to lock that bit of code:

lock (_sentence) { return _sentence ?? (_sentence = new Sentence()); } } }    

Good heavens no. That crashes immediately!

The correct thing to do is one of:

  • Stop trying to write multithreaded code.
  • Write a singleton using one of the safe singleton patterns Jon Skeet documents on his page about singletons.
  • Use the Lazy<T> class.
  • Lock on an object dedicated to locking that variable.
  • Use an Interlocked Compare Exchange to do an atomic test and set.
like image 86
Eric Lippert Avatar answered Oct 18 '22 18:10

Eric Lippert