在 C# 7 的元组之前,交换两个变量的标准方法如下:
var foo = 5;
var bar = 10;
var temp = foo;
foo = bar;
bar = temp;
但是现在我们可以使用
(foo, bar) = (bar, foo);
它在一条线上,而且更漂亮。但它是线程安全的吗?交换是原子完成的,还是这只是多步骤操作之上的糖衣?
最佳答案
“不,基本上”。
ValueTuple<...>
family 是可变的值类型,这使得它变得复杂。老的Tuple<...>
family 是不可变的引用类型; “不可变”很重要,因为它意味着它不会更改单个字段 - 它会使用所有值创建一个新对象。 “引用类型”很重要,因为这是一个单一的引用交换,它是线程安全的,因为你无法获得“撕裂的引用”。它在其他方面不是线程安全的:无法保证排序或寄存器等。
但与 ValueTuple<...>
甚至那也消失了。因为它是可变类型,所以很可能实现为多个 ldloca
/ld...
/stfld
指令,因此即使值类型不大于 CPU 宽度,也不能保证它将全部写入单个 CPU 指令中 - 而且几乎肯定不会。在“返回一个值,分配整个事物”场景中,如果足够小,它可能是单个CPU指令,但也可能不是!为了使其更加复杂,除了可变字段方法之外,还有自定义构造函数 - 但它们最终仍将写入相同的内存位置(对于值类型,目标托管引用被传递到构造函数中,而不是被传递到构造函数中。
语言或运行时不保证元组原子性;它们仅对引用和某些原语做出保证 - 另外,即使是:线程安全远不仅仅是原子性。
最后,它还取决于 objective-c PU;显然 2-int 元组不能在 32 位 CPU 上是原子的。
关于c# - C# 7 基于元组的变量交换线程安全吗?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/48550397/