Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Is C# 6 ?. (Elvis op) thread safe? If so, how?

Apologies in advance: this question comes from a hard-core, unreformed C++ developer trying to learn advanced C#. Consider the following:

if (myUserDefinedObject != null) {     myUserDefinedObject.ToString(); } 

This is obviously not thread safe. On the other hand, I've seen two tutorials that say ?. (the Null Conditional Operator or 'Elvis Operator') for example,

myUserDefinedObject?.ToString(); 

IS thread safe. Unless the compiler wraps a [mutex?] lock around it under the covers (shiver), I don't understand how that can be true. If this idiom is thread safe, can someone point me to a technical description of how that is accomplished? If it's not thread safe, does anyone have a reference that actually says it is not?

like image 782
Dick Bridges Avatar asked Mar 03 '16 23:03

Dick Bridges


People also ask

What is %C in C language?

%d is used to print decimal(integer) number ,while %c is used to print character . If you try to print a character with %d format the computer will print the ASCII code of the character.

Is C same as C+?

While both C and C++ may sound similar, their features and usage are different. C is a procedural programming language and does not support objects and classes. C++ is an enhanced version of C programming with object-oriented programming support.

Is C -- a language?

C-- (pronounced C minus minus) is a C-like programming language. Its creators, functional programming researchers Simon Peyton Jones and Norman Ramsey, designed it to be generated mainly by compilers for very high-level languages rather than written by human programmers.


2 Answers

I want to clarify BJ Myers's (correct) answer.

In C# an event can be thought of as a field of delegate type -- just as a property can be thought of as a field of the property type -- and the value of that "field" can be null. If you are in the unfortunate situation of having an event handler being modified on one thread while another thread is attempting to invoke it, you can get into the situation where:

if (this.SomeEvent != null)      this.SomeEvent( ... ); 

is not threadsafe. The value could be mutated so that it is non-null before the check, null after the check, and the program crashes.

The usual way to make this "threadsafe", and I use the term advisedly, is to copy the value to a local and then test the local for null. This has the benefit of not crashing with a null dereference. However, the clever developer will note that there is still a race! The sequence can be

  • Non-null event handler cached on thread A
  • Event handler set to null on thread B
  • State needed by event handler is destroyed on thread B
  • Event handler runs on thread A and dies horribly

So in that sense this pattern is not "thread safe". If you are in this unfortunate position you are responsible for ensuring that the appropriate threading logic is implemented so that this cannot happen. You can do that however you want. If you want the (questionable) benefits of being able to call an event handler on one thread while mutating the event on another thread, then you've got to pay either to make it safe, or deal with race condition bugs.

I personally would avoid this situation like the plague, but I'm not smart enough to write correct multithreaded code.

Now, as for the actual question:

some_expression ?. ToString(); 

is the same as

temp = some_expression temp == null ? null : temp.ToString() 

Is the latter code "threadsafe" in your opinion?

like image 96
Eric Lippert Avatar answered Sep 20 '22 23:09

Eric Lippert


From MSDN (emphasis mine):

Another use for the null-condition member access is invoking delegates in a thread-safe way with much less code. The old way requires code like the following:

var handler = this.PropertyChanged; if (handler != null)     handler(…) 

The new way is much simpler:

PropertyChanged?.Invoke(e) 

The new way is thread-safe because the compiler generates code to evaluate PropertyChanged one time only, keeping the result in temporary variable.

So there is no locking involved here - thread-safety is enforced by creating a local temporary variable, which prevents a different thread from modifying that variable in between the null check and some other operation.

like image 40
BJ Myers Avatar answered Sep 18 '22 23:09

BJ Myers