Atomic coagulation operator C #

Today, in our code base, I came across one singleton code, and I was not 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 think that??? just a compiler trick and that the resulting code is still not atomic. In other words, two or more threads could find the _ sentent equal to zero before setting the change to the new sentence and returning it.

To guarantee atomicity, we would have to block this bit of code:

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

Is it correct?

+7
source share
3 answers

You're right; it is not completely safe for threads.

+11
source

I came across some singleton code today in our code base

Do you have such confusing code throughout your code base? This code does the same:

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

and about a thousand times easier to read.

I think that??? just a trick compiler and that the resulting code is still not atomic

You're right. C # gives the following atomicity guarantees:

Read and write the following data types: atomic: bool, char, byte, sbyte, short, ushort, uint, int, float and reference. In addition, reading and writing enumeration types with a base type in the previous list are also atomic. Reads and writes of other types, including long, stole, double and decimal, as well as user-defined types, are not guaranteed to be atomic. In addition to library functions intended for this purpose, there is no guarantee of atomic read-modify-write, for example, in the case of increment or decrement.

The zero coalescence operator is not included in this list of guarantees.

To guarantee atomicity, we would have to block this bit of code:

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

Oh my god no This is a glitch immediately!

The most correct way to do this is:

  • Stop trying to write multithreaded code.
  • Write a singleton using one of the safe Jon Skeet singleton samples on your singles page.
  • Use the Lazy<T> class.
  • Locks an object intended to lock this variable.
  • Use the Interlocked Compare Exchange to perform an atomic test and installation.
+15
source

Can you use Interlocked.CompareExchange with null to get ?? - a nuclear operation that is atomic.

 // I made up my own Sentence type Sentence current = null; var whenNull = new Sentence() {Text = "Hello World!"}; var original = Interlocked.CompareExchange(ref current, new Sentence() { Text = "Hello World!" }, null); Assert.AreEqual(whenNull.Text, current.Text); Assert.IsNull(orig); // try that it won't override when not null current.Text += "!"; orig = Interlocked.CompareExchange(ref current, new Sentence() { Text = "Hello World!" }, null); Assert.AreEqual("Hello World!!", current.Text); Assert.IsNotNull(orig); 
+1
source

All Articles