Why use System.Threading.Interlocked.Decrement instead of minus?
I converted some c# code to vb.net and 开发者_运维技巧the converter.telerik.com turned this:
i--;
into this:
System.Math.Max(System.Threading.Interlocked.Decrement(i), i + 1)
Whats up with all the fancy-ness?
Michał Piaskowski's comment triggered the following explanation:
The semantics of i--
in C# are to return the current value of i
(i.e., the value before the decrement occurs) and then decrement i
by one.
So, we need to convert that to VB. We can not use i -= 1
because this does not return the current value of i
before the decrement. So, we need an operation that will decrement i
but return the value of i
before the decrement, something like:
Function DoPostDecrement(ByRef i As Integer) As Integer
i -= 1
Return i + 1
End Function
But this suggests using the following to avoid having to write a method to perform the above:
System.Math.Max(
someValueThatIsEqualToiMinusOne,
someValueThatIsEqualtoiBeforeTheDecrement
)
But VB.NET won't let you use i -= 1
or i = i - 1
in place of someValueThatIsEqualToiMinusOne
. However, System.Threading.Interlocked.Decrement(i)
is legit and equal to the value of i - 1
. Once you do that, because parameters are evaluated left to right, someValueThatIsEqualtoiBeforeTheDecrement
should be i + 1
(at that point the decrement has been performed to i + 1
is the pre-decrement value.
Note that the above method DoPostDecrement
and the System.Math.Max, System.Threading.Interlocked.Decrement
construct could have different semantics in a multithreaded context.
The Interlocked operation is atomic; in multithreaded contexts you can safely use it without holding a lock, if you're careful.
The only reason I can see is from
Interlocked.Decrement Method
Decrements a specified variable and stores the result, as an atomic operation.
It depends - is "i" a shared variable? Is it in a thread-safe environment?
If "i" is an integer, then i-- does essentially the following (ignoring the details):
- subtracts one from i
- assigns that value back to i
As you can see, there are > 1 steps. If "i" is in a non-thread-safe location (static variable shared across threads, etc), then the thread could potentially stop in the middle of those two steps, another thread could run both steps, and then you'd have a problem with invalid data.
The Interlocked class essentially combines the two steps above into a single step, providing an atomic operation. Now you don't have to worry about threads, since it's a single operation and can't be interrupted by another thread.
To answer your question, looks like this converter.telerik.com
thing is being overly-conservative about threading problems. WAAAY overly-conservative. I would revert the code to i--
if the same instance of i
isn't being mutated from multiple threads concurrently.
精彩评论