- android - 多次调用 OnPrimaryClipChangedListener
- android - 无法更新 RecyclerView 中的 TextView 字段
- android.database.CursorIndexOutOfBoundsException : Index 0 requested, 光标大小为 0
- android - 使用 AppCompat 时,我们是否需要明确指定其 UI 组件(Spinner、EditText)颜色
我想知道是否有可能将以下代码中的初始值重新排序为在计算之后导致未定义的行为。
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/
Interlocked.CompareExchange() 方法 ( docs ) 粗略地说: “我有一个变量,我想我知道它当前有什么值。如果我是对的,请将值更改为那个”。 关键是这个方法可以用来在多
伙计们, 我希望您评估下面的下一个代码。如您所见,我使用 Interlocked.CompareExchange,在这种情况下有意义吗? (我不确定它是否正确)。 如果有任何注释、评论等,我将很高兴。
我的目标是: 有一定范围的整数,我必须测试该范围内的每个整数是否随机。我想为此使用多个线程,并使用共享计数器在线程之间平均分配工作。我将计数器设置为初始值,让每个线程取一个数,增加它,进行一些计算,然
这个问题在这里已经有了答案: 关闭 10 年前。 Possible Duplicate: Interlocked.CompareExchange using GreaterThan or LessT
我想知道是否有可能将以下代码中的初始值重新排序为在计算之后导致未定义的行为。 以下例子摘自https://learn.microsoft.com/en-us/dotnet/api/system.thr
以下语句(寻址与第一个和第三个参数相同的变量)是否总是会导致变量 b 在完成时获取变量 c 的值,或者另一个线程是否有可能在获取参数时更改一个或多个参数在比较操作期间导致第一个和第三个参数包含不同的值
编译器或处理器能否重新排序以下指令,以便另一个线程看到 a == 0 和 b == 1? 假设 int a = 0, b = 0; 某处。 System.Threading.Interlocked.C
我遇到了 .NET 3.5 的 ConcurrentDictionary 实现(很抱歉我现在可以找到链接),它使用这种锁定方法: var current = Thread.CurrentThread.
我正在尝试使用 Interlocked.CompareExchange使用此枚举: public enum State { Idle, Running, //... } 以下代
我正在阅读 Joe Duffy 关于 Volatile reads and writes, and timeliness 的帖子,我正在尝试了解帖子中最后一个代码示例的一些内容: while (Int
假设你有一个属性public Foo Bar { get; } 你想延迟初始化。一种这样的方法可能是使用 Interlocked 类,它保证某些操作序列(例如递增、添加、比较交换)的原子性。你可以这样
我需要递增一个计数器直到它达到一个特定的数字。我可以使用两个并行任务来增加数字。我没有使用锁来检查数字是否未达到最大允许值然后递增,而是使用 Interlocked .CompareExchange
System.Threading.Interlocked.CompareExchange 运算符提供比较和交换操作的原子(因此线程安全)C# 实现。 例如int i = 5; Interlocked.
以下示例来自 MSDN . public class ThreadSafe { // Field totalValue contains a running total that can be
using System; using System.Threading; using System.Threading.Tasks; namespace _1._41_Compare_and_Exc
我有一个整数数组,用于跟踪 10,000 个并发任务的完成情况,其中值为 1 或 0。我认为如果这个数组是一个位数组并且每个并发线程都使用 interlocked 会更有效率。CompareExcha
来自 https://msdn.microsoft.com/en-us/library/bb297966(v=vs.110).aspx [ComVisibleAttribute(false)] pub
免责声明:我的帖子显然总是很冗长。如果您碰巧知道标题问题的答案,请随意回答,而无需阅读我下面的扩展讨论。 System.Threading.Interlocked类提供了一些非常有用的方法来帮助编写线
概要: 在我看来,这: 将表示逻辑状态的字段包装到单个不可变的消耗对象中 通过调用Interlocked.CompareExchange 更新对象的权威引用 并适当地处理更新失败 提供了一种并发性,不
在Link.TryAdd方法的dapper代码中,有如下一段代码: var snapshot = Interlocked.CompareExchange(ref head, null, null);
我是一名优秀的程序员,十分优秀!