【问题标题】:How do I check for overflow after an Interlocked.Increment in C#?如何在 C# 中的 Interlocked.Increment 之后检查溢出?
【发布时间】:2013-07-22 15:15:12
【问题描述】:

在调用Interlocked.Increment 后检查溢出的正确方法是什么?

我有一个 ID 生成器,它在程序执行期间生成唯一 ID,目前我对其进行测试,增量返回零。

public static class IdGenerator {
    private static int _counter = 0;

    public static uint GetNewId() {
        uint newId = (uint)System.Threading.Interlocked.Increment(ref _counter);
        if (newId == 0) {
             throw new System.Exception("Whoops, ran out of identifiers");
        }
        return newId;
    }
}

鉴于我每次运行生成的 ID 数量相当多,_counter 在增加时可能会溢出(在异常大的输入上),我想在这种情况下抛出异常(早早崩溃到方便调试)。

摘自Microsoft's documentation

此方法通过包装处理溢出条件:如果location = Int32.MaxValuelocation + 1 = Int32.MinValue。不抛出异常。

【问题讨论】:

  • 考虑使用long
  • 请注意(uint)int.MinValue 抛出。
  • @SLaks(你的最后一条评论)好吧,(uint)int.MinValue 作为文字不会编译。但是一个非常量变量或表达式 int i = int.MinValue 命中转换 (uint)i 不会抛出通常的 unchecked 上下文。
  • @SLaks 谢谢,我没有想到,演员表应该用unchecked 包裹起来,像这样:unchecked((uint)int.MinValue) 我想。

标签: c# integer-overflow interlocked interlocked-increment


【解决方案1】:

只需检查newId 是否为Int32.MinValue(在转换为uint 之前)并抛出异常。

从增量中获取MinValue 的唯一方法是通过溢出。

【讨论】:

  • 如果两个线程在短时间内连续增加值怎么办?
  • @JeppeStigNielsen:然后其中一个会溢出,而另一个不会。 Interlocked.Increment 的全部意义在于它是原子的;这不是问题。
  • 啊,当然,你告诉他检查Increment的返回值,而不是_counter字段的实际值。那我同意你的看法。但是他应该摆脱对uint的转换,或者其他什么。
  • @JeppeStigNielsen: newId 来自Increment()的返回值。
  • 你是对的,那里没有问题。 其他:由于他的代码在问题中,他只是将 32 位有符号整数重新解释为 无符号 32 位整数,他能够得到ID 最高为 4'294'967'295。所以他的原始代码运行良好,如果我们假设他没有使用/checked 编译器选项构建他的代码。如果他使用你的答案,他只能(大约)生成之前一半的 ID。
【解决方案2】:

考虑使用unchecked

public static class IdGenerator
{
    private static int _counter;

    public static uint GetNewId()
    {
        uint newId = unchecked ((uint) System.Threading.Interlocked.Increment(ref _counter));
        if (newId == 0)
        {
            throw new System.Exception("Whoops, ran out of identifiers");
        }
        return newId;
    }
}

在这种情况下你会得到

  1. 性能提升不大,因为编译器不会检查溢出。
  2. x2 键空间
  3. 更简单更小的代码

【讨论】:

  • 静默投票不会为社区带来任何好处。如果您认为 asnwer 是错误的/不完整的,即使您已经投了反对票,也要写下来,至少要解释您的立场。
猜你喜欢
  • 2011-01-24
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2017-10-07
  • 1970-01-01
相关资源
最近更新 更多