Search code examples
c#.netmultithreadinginterlocked

How to detect overflow (or underflow) in Interlocked.Add


I want to use an Interlocked.Add method because it's faster for int and long. I have following code for others types:

short x = Sum(source, range.Item1, range.Item2);
checked
{   
    lock (syncRoot)
        result += x;                                          
} 

But I found that Interlocked doesn't handle overflows. How can I determine that overflow or underflow occured? x can be either positive or negative.

var x = Sum(source, range.Item1, range.Item2);
Interlocked.Add(ref result, x);
bool overflow = ...
if (overflow)
   throw new OverflowException();

I found following tip on MSDN but don't know how can I implement this check:

This method handles an overflow condition by wrapping: if the value at location1 is Int32.MaxValue and value is 1, the result is Int32.MinValue; if value is 2, the result is (Int32.MinValue + 1); and so on.No exception is thrown.


Solution

  • Interlocked.Add returns the new value. If the new value is smaller than the old value then overflow occurred. The problem is that you cannot obtain the old value this way.

    You can use a CAS loop to atomically read the old value, check for overflow and atomically write the new value.

    Note, that neither locks not interlocked operations scale at all. Interlocked ops are merely hardware locks. They are faster in absolute terms and do not suffer as much from contention. But doing this operation at a high frequency will not benefit from multiple CPUs at all.