【问题标题】:How to detect overflow (or underflow) in Interlocked.Add如何检测 Interlocked.Add 中的溢出(或下溢)
【发布时间】:2016-05-22 01:53:52
【问题描述】:

我想使用Interlocked.Add 方法,因为它对于intlong 更快。我有以下其他类型的代码:

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

但我发现 Interlocked 不处理溢出。如何确定发生了上溢或下溢? x 可以是正数也可以是负数。

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

我在 MSDN 上找到了以下提示,但不知道如何实施此检查:

此方法通过包装处理溢出条件:如果值位于 location1 为 Int32.MaxValue 且值为 1,结果为 Int32.MinValue;如果值为 2,则结果为 (Int32.MinValue + 1);和 以此类推。不抛出异常。

【问题讨论】:

  • 如果你必须重新创建所有边界检查自己,这并不会更快
  • check 不适用于 double,它仅检查 integer 溢出。
  • 检查over流:Double.IsInfinity
  • @DmitryBychenko 你是对的。我为每种数字类型生成代码(因为 .Net 中的数字没有通用约束),这就是我得到这个无效代码的原因。我应该编辑我的模板文件。
  • 无法检测到溢出是非常基本的。抖动将 Interlocked.Add() 替换为实现原子增量的特定于处理器的指令。就像 Intel/Amd 处理器上的 LOCK XADD 一样。这类指令没有在溢出时产生错误的种类。而且读-测-写操作不是原子的。 Interlocked 类只适用于微优化的代码,这种代码通常具有锐利的边缘,如果需要检测溢出,则必须使用 lock 关键字。

标签: c# .net multithreading interlocked


【解决方案1】:

Interlocked.Add 返回新值。如果新值小于旧值,则发生溢出。问题是您无法通过这种方式获取旧值。

您可以使用CAS loop 原子地读取旧值、检查溢出并原子地写入新值。

请注意,无论是锁还是互锁操作都无法扩展。互锁操作仅仅是硬件锁。从绝对意义上讲,它们更快,并且不会受到争用的影响。但是以高频率执行此操作根本不会受益于多个 CPU。

【讨论】:

  • 我只是在分区上拆分一个集合,然后计算每个分区的总和。然后我将所有结果汇总为一个结果值。所以不会有更多的调用执行线程的数量,但如果可能的话,我想避免lock。在这种情况下如何实现 CAS?
  • 不幸的是,这个问题似乎没有实际意义,因为几次锁定所需的时间非常短。如果你想继续优化这个,那么谷歌一般是“.net CAS loop”或“CAS loop”。
  • 好像找到了Java的实现。我试试这个:stackoverflow.com/questions/9363419/…
  • 那段代码看起来很奇怪而且有问题。这个应该更好:software.intel.com/en-us/node/506125如果你有兴趣:jfdube.wordpress.com/2011/11/30/understanding-atomic-operations
猜你喜欢
  • 1970-01-01
  • 2023-03-22
  • 2011-01-24
  • 2014-07-20
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多