我想从多个线程中递增无符号整数。
我知道Interlocked.Increment,但它不处理无符号整数。我可以使用lock(),但如果出于性能原因,我宁愿不这样做。
线程安全只是以正常方式递增吗?如果偶尔的增量丢失也没关系,因为它只用于统计。我不想要的是腐败的价值。
答案 0 :(得分:39)
您说您出于性能原因不想使用lock
- 但是您是否对其进行了测试?一个无争议的锁(这可能是由它的声音)很便宜。
在涉及线程时(通常情况下,尤其是线程化),我通常会选择“明显正确”而不是“聪明且可能表现更好”。
使用和不使用锁定对您的应用进行基准测试,看看您是否能够注意到差异。如果锁定会产生重要的差异,那么请确保使用狡猾的东西。否则,我只是坚持锁。
} / p>
Interlocked.Increment
输出:
int
(换句话说,它没有任何问题。)
答案 1 :(得分:10)
如果你真的需要全范围的unsigned int(2 ^ 32 - 1)而不是signed int(2 ^ 31 -1),你可以转换为int64(有一个Interlocked.Increment
重载接受int64)然后转换回unsigned int。
答案 2 :(得分:2)
从 .NET 5.0 开始,无符号和有符号 Interlocked.Increment
和 int32
都有 int64
重载。
https://docs.microsoft.com/en-us/dotnet/api/system.threading.interlocked.increment?view=net-5.0
答案 3 :(得分:1)
以pre-kidney's answer为基础,您可以创建自己的帮助程序类。由于增量将在二进制级别上以相同的方式起作用,因此您可以在使用Unsafe
类进行增量之前将类型从无符号更改为有符号:
using System.Runtime.CompilerServices;
using System.Threading;
public static class InterlockedEx
{
/// <summary>
/// unsigned equivalent of <see cref="Interlocked.Increment(ref Int32)"/>
/// </summary>
public static ulong Increment(ref uint location)
{
int incrementedSigned = Interlocked.Increment(ref Unsafe.As<uint, int>(ref location));
return Unsafe.As<int, uint>(ref incrementedSigned);
}
/// <summary>
/// unsigned equivalent of <see cref="Interlocked.Increment(ref Int64)"/>
/// </summary>
public static ulong Increment(ref ulong location)
{
long incrementedSigned = Interlocked.Increment(ref Unsafe.As<ulong, long>(ref location));
return Unsafe.As<long, ulong>(ref incrementedSigned);
}
}
答案 4 :(得分:0)
在使用带符号整数的二进制补码表示的系统上(根据维基百科,"virtually all"),增加无符号整数的作用与增加使用相同位集表示的有符号整数的作用相同。因此,可以在不牺牲任何内容的情况下对无符号整数使用InterlockedIncrement。
例如,具有3位,我们有下表:
raw bits | unsigned integer | twos complement signed integer
------------------------------------------------------------
000 | 0 | 0
001 | 1 | 1
010 | 2 | 2
011 | 3 | 3
100 | 4 | -4
101 | 5 | -3
110 | 6 | -2
111 | 7 | -1
在两种情况下,递增1(并考虑溢出)等同于将表中的一项向下移动。请注意,这对于“ 1”补码算术无效,因为负数的排列顺序相反。
答案 5 :(得分:-15)
你可以将uint声明为volatile。
http://msdn.microsoft.com/en-us/library/x13ttww7(VS.71).aspx