C# 是否可以有条件地更新可为null的long而不锁定?
我已经C# 是否可以有条件地更新可为null的long而不锁定?,c#,multithreading,locking,interlocked,C#,Multithreading,Locking,Interlocked,我已经很久了?开始时间以保持开始时间 我有多个线程使用非async方法更新startTime,在一个单独的线程中有另一个async方法只读取此值。更新值的方法如下所示: if (startTime == null || (newValue != 0 && newValue < startTime)) { startTime = newValue; } if(startTime==null | |(newValue!=0&&newValue
很久了?开始时间
以保持开始时间
我有多个线程使用非async
方法更新startTime
,在一个单独的线程中有另一个async
方法只读取此值。更新值的方法如下所示:
if (startTime == null || (newValue != 0 && newValue < startTime))
{
startTime = newValue;
}
if(startTime==null | |(newValue!=0&&newValue
问题是,编写器线程正在以非常高的频率更新startTime
,导致大量锁争用。那么,有没有什么方法可以在不锁定的情况下实现这一点(或者有比普通锁更好的锁定机制)
我正在考虑使用Interlocked
,但由于if
子句,我认为这是不正确的
编辑:如果需要,我可以将其更改为不可为空。问题末尾:
编辑:如果需要,我可以将其更改为不可为空
对于不可为空的long
,您需要一个检查和更新循环(如下所示):
您可以使while子句条件任意复杂,它们实际上是您的if
检查。您可能还希望/需要在循环内重新计算newValue
联锁读取
获取初始值。Interlocated.CompareExchange执行“如果值与上次读取值时的值仍然相同,请提交我的更改”,如果值已更改,则还会获取新的当前值
其他要考虑的事情-你真的需要这个“开始时间”值还是可以在它的位置增加一个简单的整数?这将是互锁的。增量
没有循环和锁定,因此如果您可以适当地修改代码的其他部分,那么如果写入争用仍然很高,则可能值得考虑。问题结束时:
编辑:如果需要,我可以将其更改为不可为空
对于不可为空的long
,您需要一个检查和更新循环(如下所示):
您可以使while子句条件任意复杂,它们实际上是您的if
检查。您可能还希望/需要在循环内重新计算newValue
联锁读取
获取初始值。Interlocated.CompareExchange执行“如果值与上次读取值时的值仍然相同,请提交我的更改”,如果值已更改,则还会获取新的当前值
其他要考虑的事情-你真的需要这个“开始时间”值还是可以在它的位置增加一个简单的整数?这将是互锁的。增量
,没有循环和锁定,因此如果写入争用仍然很高,可能值得考虑,如果您可以适当修改代码的其他部分。您不能使用联锁
,因为它不支持可空
。您可以使用int64而不是long。@GabrielPereira,int64
是long
。联锁操作支持的最大大小是64位(至少在.NET中公开)。一个Nullable
至少是sizeof(bool)+sizeof(T)
,所以对于long
你肯定会看。我在你发布的代码中没有看到任何锁定。你不能使用联锁的,因为它不支持Nullable
。你可以用int64代替long。@GabrielPereira,Int64
是long
。联锁操作支持的最大大小为64位(至少在.NET中公开)。一个Nullable
至少是sizeof(bool)+sizeof(T)
,所以对于long
你肯定会看。我没有看到你发布的代码中有任何锁定。谢谢!如果
,为什么我们在
时使用而不是?您不必这样做,但它涵盖了“我在评估我的病情时使用的当前
的值不是现在的值”。通常,如果新值也满足了您的条件,您仍然希望将“甚至更好”newValue
放在它的位置上。所以我们循环直到条件完全不满足。(有可能在不同的条件下,newValue
会满足条件并产生一个无止境的循环,这就是为什么我总是包括额外的break
位)。谢谢!如果
,为什么我们在时使用而不是?您不必这样做,但它涵盖了“我在评估我的病情时使用的当前
的值不是现在的值”。通常,如果新值也满足了您的条件,您仍然希望将“甚至更好”newValue
放在它的位置上。所以我们循环直到条件完全不满足。(在不同的条件下,newValue
可能会满足该条件并生成一个无止境的循环,这就是为什么我总是包含额外的break
位的原因)。
var current = Interlocked.Read(ref startTime);
while(current > newValue)
{
var other = Interlocked.CompareExchange(ref startTime, newValue, current);
if(other==current) break;
current = other;
}