C# 如何以线程安全的方式递增(向)十进制数?
我有一个C# 如何以线程安全的方式递增(向)十进制数?,c#,thread-safety,C#,Thread Safety,我有一个decimal变量,可以同时从多个线程访问该变量互锁类函数根本不支持小数,因此我剩下的唯一方法就是使用lock(){}。这似乎太过分了 是否有其他方法可以以线程安全的方式向十进制变量添加值?使用锁并不过分。这是必需的 像System.Decimal这样的结构类型从来不是原子的,它也不适合本机cpu字大小。这就是为什么Interlocted也没有重载。否。十进制的内部表示太复杂,无法在CPU级别用原子指令进行修改(这是Interlocted大部分时间所做的,也是您感兴趣的) 当CPU不能自
decimal
变量,可以同时从多个线程访问该变量<代码>互锁类函数根本不支持小数,因此我剩下的唯一方法就是使用lock(){}
。这似乎太过分了
是否有其他方法可以以线程安全的方式向
十进制
变量添加值?使用锁并不过分。这是必需的
像System.Decimal这样的结构类型从来不是原子的,它也不适合本机cpu字大小。这就是为什么Interlocted也没有重载。否。
十进制
的内部表示太复杂,无法在CPU级别用原子指令进行修改(这是Interlocted
大部分时间所做的,也是您感兴趣的)
当CPU不能自动处理某些数量时,手动锁定是唯一的选择。您可以选择同步原语(例如,
lock
与mutex),但仅此而已。您仍然可以使用InterLocked
,但随后必须将十进制转换为Int64
。在转换过程中,您必须决定要保留多少位小数以保证精度。例如,要保留小数点后4位,可以这样做:
//Declare up front accessible from all threads
Int64 totalAmount = 0;
//Inside the thread you do this
var amount = (Int64)(decimalAmount * 10000); //10.000 is to preserve 4 decimal places
Interlocked.Add(ref totalAmount, amount);
//After all threads have finished, go back to decimal type.
var totalDecimalAmount = totalAmount / 10000;
请注意,您将丢失精度,具体取决于您希望保留的小数位数。和Decimal.MaxValue
是79228162514264337593543950335
,而Int64.MaxValue
是9223372036854775807
。所以非常大的数字是不合适的。保留4位小数,Int64溢出前的最大数字为9223372036854775807/10000=922337203685477
我这样使用它,因为这里的数字永远不会超过100000000,而且我确信使用
联锁
这种方式在并行中速度更快。对于循环,然后使用锁或互斥锁。如果您不介意将总数作为对象包装十进制
,您可以使用这种方法:
private static object myTotal = 0M;
static void InterlockedAddTotal(decimal val) {
object next;
object current;
do {
current = myTotal;
next = val + (decimal)current;
} while (Interlocked.CompareExchange(ref myTotal, next, current) != current);
}
尽管这种方法不使用锁,但它将decimal
包装到一个对象中,这具有其自身的性能含义。根据情况,使用锁可能更便宜。使赋值原子化的一种方法是创建一个包含十进制值的类,并将引用赋值给该类。类引用的赋值是原子的,因为它们是64(32)位的
@马尔克,放松点。平行的。因为我用过,只有完成了才可以。然后,完成/10000
操作。只要totalAmount以线程安全的方式求和,一切都很好。并非所有代码都是“关键部分”,只有求和才是关键部分<代码>totalDecimalAmount
在所有线程完成后进行评估。明白了,我真的应该更仔细地阅读代码示例注释。没有大括号、省略号或其他伪代码指示符,我只是通读了一遍。与锁定方法相比,您是否检查了此解决方案的性能?虽然此分配是原子的,但每次分配时都必须分配一个新对象,这是一个性能问题。此外,比较实例还需要覆盖Equals()
以比较它们的值
class A
{
decimal Value{get;set;}
}
var x=new A(){Value=10};
var y=new A(){Value=20};
x=y;//atomic