如何在C#中的联锁增量之后检查溢出?
调用如何在C#中的联锁增量之后检查溢出?,c#,integer-overflow,interlocked,interlocked-increment,C#,Integer Overflow,Interlocked,Interlocked Increment,调用interlocated.Increment后检查溢出的正确方法是什么? 我有一个ID生成器,在程序执行期间生成唯一的ID,目前我测试它,增量返回零 public static class IdGenerator { private static int _counter = 0; public static uint GetNewId() { uint newId = (uint)System.Threading.Interlocked.Increment
interlocated.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数量相当大,(在异常大的输入上,\u计数器
可能会在递增时溢出,在这种情况下,我希望抛出一个例外(尽早崩溃以简化调试)
摘录自:
此方法通过包装处理溢出条件:iflocation
=Int32.MaxValue
,location+1
=Int32.MinValue
。没有抛出异常
只需检查
newId
是否为Int32.MinValue
(在转换为uint
之前)并抛出异常
从增量中获取
MinValue
的唯一方法是通过溢出。考虑使用未选中的
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;
}
}
在这种情况下,你得到
性能提升很小,因为编译器不会检查溢出
x2键空间
更简单、更小的代码
如果两个线程在短时间内连续增加值会怎么样?@JeppeStigNielsen:那么其中一个线程将溢出,而另一个线程则不会。联锁的整个要点。增量
是原子的;这不是问题。啊,当然,你告诉他检查增量
的返回值,而不是\u计数器
字段的实际值。那么,我同意你的看法。但是他应该摆脱对uint
的转换,或者别的什么。@JeppeStigNielsen:newId
是Increment()
的返回值。你说得对,没有问题。还有一件事:当他的代码出现在问题中时,他只是将32位有符号整数重新解释为无符号32位整数,并且他能够获得高达4'294'967'295
的ID。因此,如果我们假设他没有使用/checked
编译器选项构建代码,那么他的原始代码运行良好。如果他使用了你的答案,他只能生成(大概)他以前能得到的一半的ID。考虑使用<代码>长< /代码>。注意:<代码>(UIN)In。MimValue/Cult>投掷。@ Salk(你的最后一个注释)好,<代码>(UIN)In。MimValue/CODE >,因为文字不会编译。但是一个非常量变量或表达式int i=int.MinValue
点击转换(uint)i
,将不会在通常的未选中的上下文中抛出。@SLaks谢谢,我没有想到,应该用未选中的(uint)int.MinValue>来包装该转换,如下所示:未选中((uint)int.MinValue)
我想是吧。沉默的向下投票不会给社区带来任何好处。如果你认为asnwer是错误的/不完整的,即使你已经投了反对票,也要写下来,至少要解释一下你的立场。