下面是一个基于Interlocked.CompareExchange的互锁方法的实现。
这段代码在重复之前使用SpinWait 自旋( spin )是否明智?
public static bool AddIfLessThan(ref int location, int value, int comparison)
{
int currentValue;
do
{
currentValue = location; // Read the current value
if (currentValue >= comparison) return false; // If "less than comparison" is NOT satisfied, return false
}
// Set to currentValue+value, iff still on currentValue; reiterate if not assigned
while (Interlocked.CompareExchange(ref location, currentValue + value, currentValue) != currentValue);
return true; // Assigned, so return true
}我见过在这个场景中使用SpinWait,但我的理论是,它应该是不必要的。毕竟,循环只包含少量的指令,并且总是有一个线程在执行过程。
假设两个线程正在竞相执行此方法,而第一个线程立即成功,而第二个线程最初不做任何更改,必须重申。没有其他竞争者,第二个线程是否有可能在第二次尝试中失败?
如果该示例的第二个线程在第二次尝试中不能失败,那么我们可以使用SpinWait获得什么?在不太可能发生的情况下,在100个线程竞相执行该方法的情况下,减少几个周期?
发布于 2019-11-04 17:27:00
我的非专家意见是,在这种特殊情况下,两个线程偶尔调用AddIfLessThan,不需要SpinWait。如果两个线程都在一个紧循环中调用AddIfLessThan,那么每个线程都可以在某个μ秒内不间断地进行进度,这可能是有益的。
实际上,我做了一个实验,测量了一个线程在紧循环中调用AddIfLessThan的性能,而不是两个线程。这两个线程几乎需要四倍的时间才能完成相同数量的循环(累计)。向混合线程添加一个SpinWait只会使两个线程比单个线程稍微慢一些。
发布于 2019-11-04 20:50:50
两个线程不是SpinWait讨论的主题。但是,这段代码并没有告诉我们有多少线程能够真正地竞争资源,使用SpinWait的线程数量相对较多,这将是有益的。特别是在线程数目较多的情况下,试图成功获取资源的虚拟线程队列变得更长,而那些最终被服务的线程很有可能超过调度器分配的时间片,这反过来会导致更高的CPU消耗,甚至会影响其他调度线程的执行。对于这种情况,SpinWait有一个很好的答案:设置一些允许的自旋上限,然后执行上下文切换。因此,在需要进行昂贵的系统调用以触发上下文切换和不受控制的用户模式CPU消耗之间是一种合理的权衡,在某些情况下,CPU消耗可能会影响其他线程的执行。
https://stackoverflow.com/questions/58696096
复制相似问题