gpt4 book ai didi

c# - Interlocked.CompareExchange 指令重新排序初始值

转载 作者:太空宇宙 更新时间:2023-11-03 14:42:27 25 4
gpt4 key购买 nike

我想知道是否有可能将以下代码中的初始值重新排序为在计算之后导致未定义的行为。

以下例子摘自https://learn.microsoft.com/en-us/dotnet/api/system.threading.interlocked.compareexchange?view=netframework-4.8

public class ThreadSafe
{
// Field totalValue contains a running total that can be updated
// by multiple threads. It must be protected from unsynchronized
// access.
private float totalValue = 0.0F;

// The Total property returns the running total.
public float Total { get { return totalValue; }}

// AddToTotal safely adds a value to the running total.
public float AddToTotal(float addend)
{
float initialValue, computedValue;
do
{
// Save the current running total in a local variable.
initialValue = totalValue;
//Do we need a memory barrier here??
// Add the new value to the running total.
computedValue = initialValue + addend;

// CompareExchange compares totalValue to initialValue. If
// they are not equal, then another thread has updated the
// running total since this loop started. CompareExchange
// does not update totalValue. CompareExchange returns the
// contents of totalValue, which do not equal initialValue,
// so the loop executes again.
}
while (initialValue != Interlocked.CompareExchange(ref totalValue,
computedValue, initialValue));
// If no other thread updated the running total, then
// totalValue and initialValue are equal when CompareExchange
// compares them, and computedValue is stored in totalValue.
// CompareExchange returns the value that was in totalValue
// before the update, which is equal to initialValue, so the
// loop ends.

// The function returns computedValue, not totalValue, because
// totalValue could be changed by another thread between
// the time the loop ends and the function returns.
return computedValue;
}
}

在将 totalvalue 分配给 initialvalue 和实际计算之间是否需要内存屏障?

正如我目前所理解的那样,可以在没有障碍的情况下以消除导致线程安全问题的初始值的方式进行优化,因为计算值可以使用陈旧值进行计算,但 CompareExchange 将不再检测到这一点:

    public float AddToTotal(float addend)
{
float computedValue;
do
{
// Add the new value to the running total.
computedValue = totalValue + addend;

// CompareExchange compares totalValue to initialValue. If
// they are not equal, then another thread has updated the
// running total since this loop started. CompareExchange
// does not update totalValue. CompareExchange returns the
// contents of totalValue, which do not equal initialValue,
// so the loop executes again.
}
while (totalValue != Interlocked.CompareExchange(ref totalValue,
computedValue, totalValue));
// If no other thread updated the running total, then
// totalValue and initialValue are equal when CompareExchange
// compares them, and computedValue is stored in totalValue.
// CompareExchange returns the value that was in totalValue
// before the update, which is equal to initialValue, so the
// loop ends.

// The function returns computedValue, not totalValue, because
// totalValue could be changed by another thread between
// the time the loop ends and the function returns.
return computedValue;
}

这里是否缺少局部变量的特殊规则来解释为什么示例不使用内存屏障?

最佳答案

CPU 永远不会以可能影响单线程执行逻辑的方式“重新排序”指令。万一

initialValue = totalValue;
computedValue = initialValue + addend;

第二个操作肯定是依赖于上一个操作中设置的值。 CPU 从其单线程逻辑角度“理解”这一点,因此该序列永远不会重新排序。然而,以下序列可以重新排序:

initialValue = totalValue;
anotherValue = totalValue;

varToInitialize = someVal;
initialized = true;

如您所见,单核执行不会受到影响,但在多核上这可能会带来一些问题。例如,如果我们围绕这样一个事实构建我们的逻辑,即如果变量 initialized 设置为 true 那么 varToInitialize 应该用某个值初始化,我们可以在多核环境中遇到麻烦:

if (initialized)
{
var storageForVal = varToInitialize; // can still be not initalized
...
// do something with storageForVal with assumption that we have correct value
}

至于局部变量。重新排序的问题是全局可见性的问题,即一个核心/CPU 对其他核心/CPU 所做的更改的可见性。局部变量主要倾向于只对单线程可见(除了一些罕见的情况,比如闭包,在方法之外公开的情况下实际上不是局部变量)所以其他线程无法访问它们并且因此其他核心/CPU 不需要它们的全局可见性。所以换句话说,在绝大多数情况下,您无需担心局部变量操作的重新排序。

关于c# - Interlocked.CompareExchange 指令重新排序初始值,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/56126472/

25 4 0
Copyright 2021 - 2024 cfsdn All Rights Reserved 蜀ICP备2022000587号
广告合作:1813099741@qq.com 6ren.com