1

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.

Ian
  • 1,221
  • 1
  • 18
  • 30
Alex Zhukovskiy
  • 9,565
  • 11
  • 75
  • 151
  • 1
    It's not faster if you then have to recreate all the bounds checking yourself anyway – James Thorpe Feb 11 '16 at 10:34
  • 5
    `check` doesn't work with `double`, it checks for *integer* overflow only. – Dmitry Bychenko Feb 11 '16 at 10:35
  • 1
    To check for *over*flow: `Double.IsInfinity` – Dmitry Bychenko Feb 11 '16 at 10:36
  • @DmitryBychenko you are right. I generate code for every number type (becuase there is no generic constraint for numbers in .Net), this is why I got this invalid code. I should edit my template file. – Alex Zhukovskiy Feb 11 '16 at 10:51
  • @JamesThorpe I thinked this way, but it's not really true, becuase `lock` affects all threads, when checking is thread-local, so 4 threads could check x4 times faster. It's better thant just lock and summarize, I guess. – Alex Zhukovskiy Feb 11 '16 at 10:52
  • 1
    It is pretty fundamental that you cannot detect overflow. The jitter replaces Interlocked.Add() by a processor-specific instruction that implements the atomic increment. Like LOCK XADD on Intel/Amd processors. These kind of instructions don't have a variety that generates a fault on overflow. And a read-test-write operation is not atomic. The Interlocked class is only suitable for micro-optimized code, with the usual sharp edges such code has, if you need to detect overflow then you have to use the *lock* keyword. – Hans Passant Feb 11 '16 at 11:10
  • @HansPassant I know that it's a micro-optimization, and I want to apply it because this code is executed very frequent. I think it should be atomically. The question is simple: is it possible to use `Interlocked` AND determine if overflow occured, maybe even if it's not efficient. If it's not efficient, it's just a question `good-to-know` if not practical. – Alex Zhukovskiy Feb 11 '16 at 11:36
  • Somewhat related: [How should I increment a number for a round robin threading scenario with least contention?](https://stackoverflow.com/questions/10034289/how-should-i-increment-a-number-for-a-round-robin-threading-scenario-with-least) – Theodor Zoulias Feb 08 '21 at 05:30

1 Answers1

1

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.

usr
  • 168,620
  • 35
  • 240
  • 369
  • I just split a collection on partitions, and then calculating sum of each partition. Then I summarize all results in one result value. So it won't be more calls that number of executing threads, but I want to avoid `lock` if possible. How CAS could be implemented in this case? – Alex Zhukovskiy Feb 11 '16 at 11:39
  • 1
    Unfortunately, it seems the question is moot because the time it takes to take a lock a few times is extremely low. If you want to continue to optimize this then Google for ".net CAS loop" or "CAS loop" in general. – usr Feb 11 '16 at 11:41
  • It seems that I found an implementation in Java. I'l try this one: http://stackoverflow.com/questions/9363419/greater-than-compare-and-swap – Alex Zhukovskiy Feb 11 '16 at 11:46
  • 1
    That code looks weird and broken. This should be better: https://software.intel.com/en-us/node/506125 In case you are interested: https://jfdube.wordpress.com/2011/11/30/understanding-atomic-operations/ – usr Feb 11 '16 at 11:51