Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Does C# ++ operator become threadsafe in foreach loop?

Recently I moved from VB to C#, so I often use a C# to VB.NET converter to understand syntax differences. While moving next method to VB I noticed an interesting thing.

C# original code:

 public bool ExceedsThreshold(int threshold, IEnumerable<bool> bools)
{
   int trueCnt = 0;
   foreach(bool b in bools)
      if (b && (++trueCnt > threshold)) 
          return true;
   return false;          
} 

VB.NET result:

Public Function ExceedsThreshold(threshold As Integer, bools As IEnumerable(Of Boolean)) As Boolean
Dim trueCnt As Integer = 0
For Each b As Boolean In bools
    If b AndAlso (System.Threading.Interlocked.Increment(trueCnt) > threshold) Then
        Return True
    End If
Next
Return False End Function

C#'s ++ operator replaced with System.Threading.Interlocked.Increment Does it mean that not threadsafe ++ operator become threadsafe if used in foreach loop? Is it a kind of syntax sugar? If that is true, then why converter placed Interlocked.Increment in VB version? I thought foreach in both C# and VB works exactly the same. Or it's just a converter "insurance"?

like image 736
AsValeO Avatar asked Apr 04 '15 17:04

AsValeO


People also ask

What is the --> operator in C?

It is used with a pointer variable pointing to a structure or union. The arrow operator is formed by using a minus sign, followed by the greater than symbol as shown below. Operation: The -> operator in C or C++ gives the value held by variable_name to structure or union variable pointer_name.

What does != Mean in C?

The not-equal-to operator ( != ) returns true if the operands don't have the same value; otherwise, it returns false .


3 Answers

I'm sure it's simply a converter hack, and I think I can explain the reasoning behind this.

But first, just to answer your question, the built-in ++ operator in C# is not thread-safe. It's simply a syntactic sugar for the following process (in the case of ++i):

  • read the value of i
  • increment it
  • write it back to i
  • return the incremented value

As there's a separate read and write, this is a non-atomic operation.

Now, in VB there is no direct equivalent of the ++ operator. The closest thing is:

i += 1

but this is a statement. By contrast, ++i is an expression. You can use ++i inside another statement or expression, but you can't do so with VB statements.

Using Interlocked.Increment is only a clever way to translate the code easily, without having to break down the whole statement into multiple other statements.

Without this trick, the converter would have to break down the expression like this:

if (b && (++trueCnt > threshold))
    ...
If b Then
    trueCnt += 1
    If trueCnt > threshold Then
        ...
    End If
End If

Which, as you can see, requires much more rewriting. It would even require introducing a separate temporary variable if trueCnt were a property (to avoid evaluating it twice).

This requires a deeper semantic analysis and control flow rewriting than the simpler syntactic conversion your converter used - just because trueCnt += 1 can't be used inside an expression in VB.

like image 128
Lucas Trzesniewski Avatar answered Oct 01 '22 23:10

Lucas Trzesniewski


I believe it's because you're wanting to increment the value in the same statement as doing the comparison. I don't have too much justification for that, but it sure feels like the right answer as trueCnt += 1 doesn't allow a comparison in the same line. It certainly has nothing to do with it being a foreach, try and add the same line outside the loop and I am almost certain it will convert to Increment also. There's simply no other syntax in VB .Net to both increment and compare in the same line.

like image 39
Callum Bradbury Avatar answered Oct 02 '22 00:10

Callum Bradbury


In addition to the aforementioned issues, the default behavior of C# follows Java's unfortunate integer-overflow behavior. Although there are times when wrapping integer-overflow semantics are useful, C# generally makes no distinction between situations where integers should wrap on overflow versus those where integers aren't expected to wrap but the programmer doesn't think overflow trapping is worthwhile. This can muddle conversion efforts because VB.NET makes trapping behavior easier and faster than wrapping behavior, while C# does the reverse. Consequently, the logical way to translate code which uses unchecked math for reasons of speed would be to use ordinary checked math in VB.NET, while the logical way to translate code which needs wrapping behavior would be to use wrapping integer methods in VB.NET. The Threading.Interlocked.Increment and Threading.Increment.Add methods use wrapping integer behavior, so while they're not optimal from a speed perspective they are convenient.

like image 31
supercat Avatar answered Oct 01 '22 23:10

supercat